Skip to content

Commit 17370dc

Browse files
sofislyoshi-automationbcoe
authoredApr 8, 2022
fix: do not stringify form data (#475)
* fix: do not stringify form data Co-authored-by: yoshi-automation <yoshi-automation@google.com> Co-authored-by: Benjamin E. Coe <bencoe@google.com>
1 parent 6550014 commit 17370dc

File tree

3 files changed

+34
-9
lines changed

3 files changed

+34
-9
lines changed
 

‎package.json

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"cors": "^2.8.5",
5858
"execa": "^5.0.0",
5959
"express": "^4.16.4",
60+
"form-data": "^4.0.0",
6061
"gts": "^3.0.0",
6162
"is-docker": "^2.0.0",
6263
"karma": "^6.0.0",

‎src/gaxios.ts

+16-9
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,10 @@ export class Gaxios {
236236

237237
opts.headers = opts.headers || {};
238238
if (opts.data) {
239+
const isFormData =
240+
typeof FormData === 'undefined'
241+
? false
242+
: opts?.data instanceof FormData;
239243
if (isStream.readable(opts.data)) {
240244
opts.body = opts.data;
241245
} else if (hasBuffer() && Buffer.isBuffer(opts.data)) {
@@ -247,16 +251,19 @@ export class Gaxios {
247251
} else if (typeof opts.data === 'object') {
248252
// If www-form-urlencoded content type has been set, but data is
249253
// provided as an object, serialize the content using querystring:
250-
if (
251-
getHeader(opts, 'content-type') ===
252-
'application/x-www-form-urlencoded'
253-
) {
254-
opts.body = opts.paramsSerializer(opts.data);
255-
} else {
256-
if (!hasHeader(opts, 'Content-Type')) {
257-
opts.headers['Content-Type'] = 'application/json';
254+
if (!isFormData) {
255+
if (
256+
getHeader(opts, 'content-type') ===
257+
'application/x-www-form-urlencoded'
258+
) {
259+
opts.body = opts.paramsSerializer(opts.data);
260+
} else {
261+
// } else if (!(opts.data instanceof FormData)) {
262+
if (!hasHeader(opts, 'Content-Type')) {
263+
opts.headers['Content-Type'] = 'application/json';
264+
}
265+
opts.body = JSON.stringify(opts.data);
258266
}
259-
opts.body = JSON.stringify(opts.data);
260267
}
261268
} else {
262269
opts.body = opts.data;

‎test/test.getch.ts

+17
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
import qs from 'querystring';
3131
import fs from 'fs';
3232
import {Blob} from 'node-fetch';
33+
global.FormData = require('form-data');
3334

3435
nock.disableNetConnect();
3536

@@ -381,6 +382,22 @@ describe('🥁 configuration options', () => {
381382
assert.deepStrictEqual(res.config.data, body);
382383
});
383384

385+
it('should not stringify the data if it is appended by a form', async () => {
386+
const formData = new FormData();
387+
formData.append('test', '123');
388+
// I don't think matching formdata is supported in nock, so skipping: https://github.com/nock/nock/issues/887
389+
const scope = nock(url).post('/').reply(200);
390+
const res = await request({
391+
url,
392+
method: 'POST',
393+
data: formData,
394+
});
395+
scope.done();
396+
assert.deepStrictEqual(res.config.data, formData);
397+
assert.ok(res.config.data instanceof FormData);
398+
assert.deepEqual(res.config.body, undefined);
399+
});
400+
384401
it('should allow explicitly setting the fetch implementation to node-fetch', async () => {
385402
const scope = nock(url).get('/').reply(200);
386403
const res = await request({url, fetchImplementation: fetch});

0 commit comments

Comments
 (0)
Please sign in to comment.