Skip to content

Commit

Permalink
fix!: examine response content-type if no contentType is set (#535)
Browse files Browse the repository at this point in the history
* fix: examine response content-type if no contentType is set

* pin compodoc dep to 1.1.19

* update README with unknown responseType

---------

Co-authored-by: sofisl <55454395+sofisl@users.noreply.github.com>
  • Loading branch information
ddelgrosso1 and sofisl committed Jul 11, 2023
1 parent afadf82 commit cd8ca7b
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 7 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ over other authentication methods, i.e., application default credentials.
};

// The expected return type of the request. Options are:
// json | stream | blob | arraybuffer | text
// Defaults to `json`.
responseType: 'json',
// json | stream | blob | arraybuffer | text | unknown
// Defaults to `unknown`.
responseType: 'unknown',

// The node.js http agent to use for the request.
agent: someHttpsAgent,
Expand Down
8 changes: 7 additions & 1 deletion src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,13 @@ export interface GaxiosOptions {
* @deprecated ignored
*/
onUploadProgress?: (progressEvent: any) => void;
responseType?: 'arraybuffer' | 'blob' | 'json' | 'text' | 'stream';
responseType?:
| 'arraybuffer'
| 'blob'
| 'json'
| 'text'
| 'stream'
| 'unknown';
agent?: Agent | ((parsedUrl: URL) => Agent);
validateStatus?: (status: number) => boolean;
retryConfig?: RetryConfig;
Expand Down
31 changes: 29 additions & 2 deletions src/gaxios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ export class Gaxios {
case 'blob':
return res.blob();
default:
return res.text();
return this.getResponseDataFromContentType(res);
}
}

Expand Down Expand Up @@ -282,7 +282,7 @@ export class Gaxios {
}

opts.validateStatus = opts.validateStatus || this.validateStatus;
opts.responseType = opts.responseType || 'json';
opts.responseType = opts.responseType || 'unknown';
if (!opts.headers['Accept'] && opts.responseType === 'json') {
opts.headers['Accept'] = 'application/json';
}
Expand Down Expand Up @@ -364,4 +364,31 @@ export class Gaxios {
},
};
}

/**
* Attempts to parse a response by looking at the Content-Type header.
* @param {FetchResponse} response the HTTP response.
* @returns {Promise<any>} a promise that resolves to the response data.
*/
private getResponseDataFromContentType(
response: FetchResponse
): Promise<any> {
let contentType = response.headers.get('Content-Type');
if (contentType === null) {
// Maintain existing functionality by calling text()
return response.text();
}
contentType = contentType.toLowerCase();
if (contentType.includes('application/json')) {
return response.json();
} else if (
contentType.includes('text/plain') ||
contentType.includes('text/html')
) {
return response.text();
} else {
// If the content type is something not easily handled, just return the raw data (blob)
return response.blob();
}
}
}
35 changes: 34 additions & 1 deletion test/test.getch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ describe('🥁 configuration options', () => {
.matchHeader('accept', 'application/json')
.get('/')
.reply(200, {});
const res = await request({url});
const res = await request({url, responseType: 'json'});
scope.done();
assert.deepStrictEqual(res.data, {});
});
Expand Down Expand Up @@ -575,6 +575,39 @@ describe('🎏 data handling', () => {
assert.ok(res.data);
assert.strictEqual(res.statusText, 'OK');
});

it('should return JSON when response Content-Type=application/json', async () => {
const body = {hello: 'world'};
const scope = nock(url)
.get('/')
.reply(200, body, {'Content-Type': 'application/json'});
const res = await request({url});
scope.done();
assert.ok(res.data);
assert.deepStrictEqual(res.data, body);
});

it('should return text when response Content-Type=text/plain', async () => {
const body = 'hello world';
const scope = nock(url)
.get('/')
.reply(200, body, {'Content-Type': 'text/plain'});
const res = await request({url});
scope.done();
assert.ok(res.data);
assert.deepStrictEqual(res.data, body);
});

it('should return raw data when Content-Type is unable to be parsed', async () => {
const body = Buffer.from('hello world', 'utf-8');
const scope = nock(url)
.get('/')
.reply(200, body, {'Content-Type': 'image/gif'});
const res = await request({url});
scope.done();
assert.ok(res.data);
assert.notEqual(res.data, body);
});
});

describe('🍂 defaults & instances', () => {
Expand Down

0 comments on commit cd8ca7b

Please sign in to comment.