Skip to content

Commit 666684a

Browse files
committed
Handle ApiError without axios response
1 parent f3084ba commit 666684a

2 files changed

Lines changed: 102 additions & 9 deletions

File tree

src/model/ApiError.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,21 @@ export class ApiError {
3131
request: Request
3232

3333
constructor(axiosError) {
34+
const response = axiosError.response || {};
35+
const request = axiosError.request || {};
3436

35-
this.statusCode = axiosError.response.status;
36-
this.body = axiosError.response.data;
37-
this.headers = axiosError.response.headers;
37+
this.statusCode = response.status || 0;
38+
this.body = response.data ?? axiosError.message;
39+
this.headers = response.headers || {};
3840
this.request = {
3941
url: {
40-
protocol: axiosError.request.protocol,
41-
port: axiosError.request.agent?.defaultPort || axiosError.request.socket?.localPort,
42-
host: axiosError.request.host,
43-
path: axiosError.request.path,
42+
protocol: request.protocol,
43+
port: request.agent?.defaultPort || request.socket?.localPort,
44+
host: request.host,
45+
path: request.path,
4446
},
45-
headers: axiosError.request.getHeaders(),
46-
method: axiosError.request.method
47+
headers: typeof request.getHeaders === 'function' ? request.getHeaders() : {},
48+
method: request.method
4749
}
4850
}
4951

src/test/apiError.spec.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { ApiError } from '../model/ApiError';
2+
3+
describe('ApiError', () => {
4+
it('handles axios errors without a response', () => {
5+
const apiError = new ApiError({
6+
message: 'Network Error',
7+
request: {
8+
protocol: 'https:',
9+
agent: {
10+
defaultPort: 443,
11+
},
12+
host: 'api.xero.com',
13+
path: '/api.xro/2.0/Invoices',
14+
getHeaders: () => ({
15+
authorization: 'Bearer token',
16+
}),
17+
method: 'GET',
18+
},
19+
});
20+
21+
expect(apiError.generateError()).toEqual({
22+
response: {
23+
statusCode: 0,
24+
body: 'Network Error',
25+
headers: {},
26+
request: {
27+
url: {
28+
protocol: 'https:',
29+
port: 443,
30+
host: 'api.xero.com',
31+
path: '/api.xro/2.0/Invoices',
32+
},
33+
headers: {
34+
authorization: 'Bearer token',
35+
},
36+
method: 'GET',
37+
},
38+
},
39+
body: 'Network Error',
40+
});
41+
});
42+
43+
it('preserves axios response details when available', () => {
44+
const apiError = new ApiError({
45+
response: {
46+
status: 401,
47+
data: {
48+
error: 'invalid_token',
49+
},
50+
headers: {
51+
'content-type': 'application/json',
52+
},
53+
},
54+
request: {
55+
protocol: 'https:',
56+
socket: {
57+
localPort: 443,
58+
},
59+
host: 'api.xero.com',
60+
path: '/api.xro/2.0/Invoices',
61+
getHeaders: () => ({}),
62+
method: 'GET',
63+
},
64+
});
65+
66+
expect(apiError.generateError()).toEqual({
67+
response: {
68+
statusCode: 401,
69+
body: {
70+
error: 'invalid_token',
71+
},
72+
headers: {
73+
'content-type': 'application/json',
74+
},
75+
request: {
76+
url: {
77+
protocol: 'https:',
78+
port: 443,
79+
host: 'api.xero.com',
80+
path: '/api.xro/2.0/Invoices',
81+
},
82+
headers: {},
83+
method: 'GET',
84+
},
85+
},
86+
body: {
87+
error: 'invalid_token',
88+
},
89+
});
90+
});
91+
});

0 commit comments

Comments
 (0)