diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d2c1861..efb78236 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ - Implement an in-memory cache store to save parsed and validated documents and provide performance benefits for successful executions of the same document. [PR #2111](https://github.com/apollographql/apollo-server/pull/2111) (`2.4.0-alpha.0`) - New `apollo-server-fastify` integration ([@rkorrelboom](https://github.com/rkorrelboom) in [#1971](https://github.com/apollostack/apollo-server/pull/1971)) +- Fix: Serialize arrays as JSON on fetch in `RESTDataSource`. [PR #2219](https://github.com/apollographql/apollo-server/pull/2219) + ### v2.3.3 - `apollo-server` (only): Stop double-invocation of `serverWillStart` life-cycle event. (More specific integrations - e.g. Express, Koa, Hapi, etc. - were unaffected.) [PR #2239](https://github.com/apollographql/apollo-server/pull/2239) diff --git a/package-lock.json b/package-lock.json index f5d29d91..6791d318 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1347,9 +1347,9 @@ } }, "@types/jest": { - "version": "23.3.13", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-23.3.13.tgz", - "integrity": "sha512-ePl4l+7dLLmCucIwgQHAgjiepY++qcI6nb8eAwGNkB6OxmTe3Z9rQU3rSpomqu42PCCnlThZbOoxsf+qylJsLA==", + "version": "23.3.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-23.3.14.tgz", + "integrity": "sha512-Q5hTcfdudEL2yOmluA1zaSyPbzWPmJ3XfSWeP3RyoYvS9hnje1ZyagrZOuQ6+1nQC1Gw+7gap3pLNL3xL6UBug==", "dev": true }, "@types/joi": { @@ -6733,9 +6733,9 @@ } }, "hapi": { - "version": "17.8.3", - "resolved": "https://registry.npmjs.org/hapi/-/hapi-17.8.3.tgz", - "integrity": "sha512-HH+w5qxtEdnYgwYdeqUbVi7VnWWHl1U2eW6tyu6P681VhJimGYgDBpbcqCjKta61yWS27E1LG8rNLj+0Renj4w==", + "version": "17.8.4", + "resolved": "https://registry.npmjs.org/hapi/-/hapi-17.8.4.tgz", + "integrity": "sha512-KmW0a36iXesMKKGNI4J/Ht37f2HQP6W6iKce8U5lxf+GtSH70zSh7q3D56Ro/a4Q5U5M60gSSU4esMVFxttANQ==", "dev": true, "requires": { "accept": "3.x.x", @@ -6812,9 +6812,9 @@ } }, "bourne": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/bourne/-/bourne-1.0.0.tgz", - "integrity": "sha512-938G7p21n3x3FiGnZcoN8Spv7EHOgFRnUStCby2/2fYnkY+fFU5TobsN4xCo5kW/jniYJP8KWjBFTzM4oq+ewg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/bourne/-/bourne-1.1.1.tgz", + "integrity": "sha512-Ou0l3W8+n1FuTOoIfIrCk9oF9WVWc+9fKoAl67XQr9Ws0z7LgILRZ7qtc9xdT4BveSKtnYXfKPgn8pFAqeQRew==", "dev": true }, "call": { diff --git a/package.json b/package.json index 4e349b6b..26f0e3bd 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "@types/fibers": "0.0.30", "@types/graphql": "14.0.5", "@types/hapi": "17.8.5", - "@types/jest": "23.3.13", + "@types/jest": "23.3.14", "@types/koa-multer": "1.0.0", "@types/koa-router": "7.0.39", "@types/lodash": "4.14.120", @@ -104,7 +104,7 @@ "graphql-subscriptions": "1.0.0", "graphql-tag": "2.10.1", "graphql-tools": "4.0.4", - "hapi": "17.8.3", + "hapi": "17.8.4", "husky": "1.3.1", "jest": "23.6.0", "jest-junit": "5.2.0", diff --git a/packages/apollo-datasource-rest/src/RESTDataSource.ts b/packages/apollo-datasource-rest/src/RESTDataSource.ts index 0c8f9bf1..26d7a492 100644 --- a/packages/apollo-datasource-rest/src/RESTDataSource.ts +++ b/packages/apollo-datasource-rest/src/RESTDataSource.ts @@ -218,11 +218,12 @@ export abstract class RESTDataSource extends DataSource { url.searchParams.append(name, value); } - // We accept arbitrary objects as body and serialize them as JSON + // We accept arbitrary objects and arrays as body and serialize them as JSON if ( options.body !== undefined && options.body !== null && (options.body.constructor === Object || + Array.isArray(options.body) || ((options.body as any).toJSON && typeof (options.body as any).toJSON === 'function')) ) { diff --git a/packages/apollo-datasource-rest/src/__tests__/RESTDataSource.test.ts b/packages/apollo-datasource-rest/src/__tests__/RESTDataSource.test.ts index 48868de3..477ad4cc 100644 --- a/packages/apollo-datasource-rest/src/__tests__/RESTDataSource.test.ts +++ b/packages/apollo-datasource-rest/src/__tests__/RESTDataSource.test.ts @@ -268,6 +268,31 @@ describe('RESTDataSource', () => { ); }); + it('serializes a request body that is an array as JSON', async () => { + const dataSource = new class extends RESTDataSource { + baseURL = 'https://api.example.com'; + + postFoo(foo) { + return this.post('foo', foo); + } + }(); + + dataSource.httpCache = httpCache; + + fetch.mockJSONResponseOnce(); + + await dataSource.postFoo(['foo', 'bar']); + + expect(fetch.mock.calls.length).toEqual(1); + expect(fetch.mock.calls[0][0].url).toEqual('https://api.example.com/foo'); + expect(fetch.mock.calls[0][0].body).toEqual( + JSON.stringify(['foo', 'bar']), + ); + expect(fetch.mock.calls[0][0].headers.get('Content-Type')).toEqual( + 'application/json', + ); + }); + it('serializes a request body that has a toJSON method as JSON', async () => { const dataSource = new class extends RESTDataSource { baseURL = 'https://api.example.com';