Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: translate GaxiosError message to object regardless of return type (return data as default) #546

Merged
merged 7 commits into from
Jul 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export class GaxiosError<T = any> extends Error {
super(message);
this.response = response;
this.config = options;
this.response.data = translateData(options.responseType, response.data);
this.code = response.status.toString();
}
}
Expand Down Expand Up @@ -202,3 +203,18 @@ export interface FetchHeaders {
thisArg?: any
): void;
}

function translateData(responseType: string | undefined, data: any) {
switch (responseType) {
case 'stream':
return data;
case 'json':
return JSON.parse(JSON.stringify(data));
case 'arraybuffer':
return JSON.parse(Buffer.from(data).toString('utf8'));
case 'blob':
return JSON.parse(data.text());
default:
return data;
}
}
11 changes: 11 additions & 0 deletions src/gaxios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
Headers,
} from './common';
import {getRetryConfig} from './retry';
import {Stream} from 'stream';

/* eslint-disable @typescript-eslint/no-explicit-any */

Expand Down Expand Up @@ -155,6 +156,16 @@ export class Gaxios {
translatedResponse = await this._defaultAdapter(opts);
}
if (!opts.validateStatus!(translatedResponse.status)) {
if (opts.responseType === 'stream') {
let response = '';
await new Promise(resolve => {
(translatedResponse.data as Stream).on('data', chunk => {
response += chunk;
});
(translatedResponse.data as Stream).on('end', resolve);
});
translatedResponse.data = response as T;
}
throw new GaxiosError<T>(
`Request failed with status code ${translatedResponse.status}`,
opts,
Expand Down
43 changes: 43 additions & 0 deletions test/test.getch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,49 @@ describe('🚙 error handling', () => {
return err.code === '500';
});
});

it('should throw the error as a GaxiosError object, regardless of Content-Type header', async () => {
const body = {
error: {
code: 404,
message: 'File not found',
},
};
const scope = nock(url).get('/').reply(404, body);
await assert.rejects(
request<JSON>({url, responseType: 'json'}),
(err: GaxiosError) => {
scope.done();
return (
err.code === '404' &&
err.message === 'Request failed with status code 404' &&
err.response?.data.error.message === 'File not found'
);
}
);
});

it('should throw the error as a GaxiosError object (with the message as a string), even if the request type is requested as an arraybuffer', async () => {
const body = {
error: {
code: 404,
message: 'File not found',
},
};
const scope = nock(url).get('/').reply(404, body);

await assert.rejects(
request<ArrayBuffer>({url, responseType: 'arraybuffer'}),
(err: GaxiosError) => {
scope.done();
return (
err.code === '404' &&
err.message === 'Request failed with status code 404' &&
err.response?.data.error.message === 'File not found'
);
}
);
});
});

describe('🥁 configuration options', () => {
Expand Down