diff --git a/src/common.ts b/src/common.ts index 4513cdc3..5160ecef 100644 --- a/src/common.ts +++ b/src/common.ts @@ -28,6 +28,7 @@ export class GaxiosError extends Error { super(message); this.response = response; this.config = options; + this.response.data = translateData(options.responseType, response.data); this.code = response.status.toString(); } } @@ -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 JSON.parse(data.text()); + } +} diff --git a/src/gaxios.ts b/src/gaxios.ts index 7267af30..fc535ca6 100644 --- a/src/gaxios.ts +++ b/src/gaxios.ts @@ -28,6 +28,7 @@ import { Headers, } from './common'; import {getRetryConfig} from './retry'; +import {Stream} from 'stream'; /* eslint-disable @typescript-eslint/no-explicit-any */ @@ -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( `Request failed with status code ${translatedResponse.status}`, opts, diff --git a/test/test.getch.ts b/test/test.getch.ts index 0297a188..c3397db9 100644 --- a/test/test.getch.ts +++ b/test/test.getch.ts @@ -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({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({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', () => {