diff --git a/CHANGELOG.md b/CHANGELOG.md index f9b2e5acb09..dd089c2e8b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,6 @@ ### vNEXT (v2.4.0) - 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) - Fix: The `privateHeaders` configuration for `apollo-engine-reporting` now allows headers to be specified using any case and lower-cases them prior to comparison. [PR #2276](https://github.com/apollographql/apollo-server/pull/2276) diff --git a/README.md b/README.md index d2153a300fe..a5c413a7b95 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,6 @@ Often times, Apollo Server needs to be run with a particular integration. To sta - `apollo-server-express` - `apollo-server-koa` - `apollo-server-hapi` -- `apollo-server-fastify` - `apollo-server-lambda` - `apollo-server-azure-functions` - `apollo-server-cloud-functions` @@ -236,25 +235,6 @@ new ApolloServer({ }) ``` -## Fastify - -```js -const { ApolloServer, gql } = require('apollo-server-fastify'); -const { typeDefs, resolvers } = require('./module'); - -const server = new ApolloServer({ - typeDefs, - resolvers, -}); - -const app = require('fastify')(); - -(async function () { - app.register(server.createHandler()); - await app.listen(3000); -})(); -``` - ### AWS Lambda Apollo Server can be run on Lambda and deployed with AWS Serverless Application Model (SAM). It requires an API Gateway with Lambda Proxy Integration. diff --git a/package-lock.json b/package-lock.json index 6791d31855b..943c5fbd54b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1511,16 +1511,6 @@ "@types/node": "*" } }, - "@types/pino": { - "version": "4.16.1", - "resolved": "https://registry.npmjs.org/@types/pino/-/pino-4.16.1.tgz", - "integrity": "sha512-uYEhZ3jsuiYFsPcR34fbxVlrqzqphc+QQ3fU4rWR6PXH8ka2TKvPBjtkNqj8oBHouVGf4GCRfyPb7FG2TEtPZA==", - "dev": true, - "requires": { - "@types/events": "*", - "@types/node": "*" - } - }, "@types/podium": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/podium/-/podium-1.0.0.tgz", @@ -1636,12 +1626,6 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, - "abstract-logging": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/abstract-logging/-/abstract-logging-1.0.0.tgz", - "integrity": "sha1-i33q/TEFWbwo93ck3RuzAXcnjBs=", - "dev": true - }, "accept": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/accept/-/accept-3.0.2.tgz", @@ -2289,17 +2273,6 @@ } } }, - "apollo-server-fastify": { - "version": "file:packages/apollo-server-fastify", - "requires": { - "@apollographql/graphql-playground-html": "^1.6.6", - "apollo-server-core": "file:packages/apollo-server-core", - "fastify-accepts": "^0.5.0", - "fastify-cors": "^0.2.0", - "graphql-subscriptions": "^1.0.0", - "graphql-tools": "^4.0.0" - } - }, "apollo-server-hapi": { "version": "file:packages/apollo-server-hapi", "requires": { @@ -2608,33 +2581,6 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, - "avvio": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/avvio/-/avvio-5.9.0.tgz", - "integrity": "sha512-bzgrSPRdU1T/AkhEuXWAA6cJCFA3zApLk+5fkpcQt4US9YAI52AFYnsGX1HSCF2bHSltEYfk7fbffYu4WnazmA==", - "dev": true, - "requires": { - "debug": "^3.1.0", - "fastq": "^1.6.0" - }, - "dependencies": { - "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", - "dev": true - } - } - }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -4186,12 +4132,6 @@ "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", "dev": true }, - "deepmerge": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-3.0.0.tgz", - "integrity": "sha512-a8z8bkgHsAML+uHLqmMS83HHlpy3PvZOOuiTQqaa3wu8ZVg3h0hqHk6aCsGdOnZV2XMM/FRimNGjUh0KCcmHBw==", - "dev": true - }, "default-require-extensions": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz", @@ -4835,12 +4775,6 @@ "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", "dev": true }, - "fast-decode-uri-component": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.0.tgz", - "integrity": "sha512-WQSYVKn6tDW/3htASeUkrx5LcnuTENQIZQPCVlwdnvIJ7bYtSpoJYq38MgUJnx1CQIR1gjZ8HJxAEcN4gqugBg==", - "dev": true - }, "fast-deep-equal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", @@ -5173,157 +5107,17 @@ } } }, - "fast-json-parse": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz", - "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==", - "dev": true - }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, - "fast-json-stringify": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-1.10.0.tgz", - "integrity": "sha512-qO+GSdwCQHXJjoRbS/pYJzzz8BNUrCk0jdPhDg68mdIG/hOC0k66PUKFz300LAH42vNQkuPFvpwa0JV44ZG3Uw==", - "dev": true, - "requires": { - "ajv": "^6.5.4", - "deepmerge": "^3.0.0" - }, - "dependencies": { - "ajv": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.2.tgz", - "integrity": "sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - } - } - }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "fast-safe-stringify": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-1.2.3.tgz", - "integrity": "sha512-QJYT/i0QYoiZBQ71ivxdyTqkwKkQ0oxACXHYxH2zYHJEgzi2LsbjgvtzTbLi1SZcF190Db2YP7I7eTsU2egOlw==", - "dev": true - }, - "fastify": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastify/-/fastify-1.13.0.tgz", - "integrity": "sha512-0aqsHEk2WtgGxPVDTOqDLv5XLHQE2EuH7eCq4XRLLnktLehNvr3/Afi/nEn6pPoLiVGMrbWHv4l1+wDhiSIFoA==", - "dev": true, - "requires": { - "@types/pino": "^4.16.0", - "abstract-logging": "^1.0.0", - "ajv": "^6.5.4", - "avvio": "^5.8.0", - "end-of-stream": "^1.4.1", - "fast-json-stringify": "^1.8.0", - "find-my-way": "^1.15.3", - "flatstr": "^1.0.8", - "light-my-request": "^3.0.0", - "middie": "^3.1.0", - "pino": "^4.17.3", - "proxy-addr": "^2.0.3", - "tiny-lru": "^1.6.1" - }, - "dependencies": { - "ajv": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.2.tgz", - "integrity": "sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - } - } - }, - "fastify-accepts": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/fastify-accepts/-/fastify-accepts-0.5.0.tgz", - "integrity": "sha1-wXwgEnjyv8Ub+5P/5I78T8QP02M=", - "requires": { - "accepts": "^1.3.3", - "fastify-plugin": "^0.2.1" - } - }, - "fastify-cors": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/fastify-cors/-/fastify-cors-0.2.0.tgz", - "integrity": "sha512-bw14FmjHm8oF4TDLkwj2TpssH6O2gE0NpsRqLe7F1Gh9Jf30Lx9ZzIznhqaAKOYS+LJqLIt5snurv7urgqYntA==", - "requires": { - "fastify-plugin": "^1.2.0", - "vary": "^1.1.2" - }, - "dependencies": { - "fastify-plugin": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-1.4.0.tgz", - "integrity": "sha512-l6uqDyBp3gBjLQRAi3j2NwSvlbe9LuqULZugnO9iRFfYHWd2SpsZBLI1l4Jakk0VMGfYlB322JPIPYh/2qSHig==", - "requires": { - "semver": "^5.5.0" - } - } - } - }, - "fastify-plugin": { - "version": "0.2.2", - "resolved": "http://registry.npmjs.org/fastify-plugin/-/fastify-plugin-0.2.2.tgz", - "integrity": "sha512-oRJdjdudgCkQQUARNeh2rkbxFAmj2OhCJSVBNBLUbhS0orF+IMQ4u/bc661N1jh/wDI2J+YKmXmmHSVFQI4e7A==", - "requires": { - "semver": "^5.4.1" - } - }, - "fastq": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz", - "integrity": "sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==", - "dev": true, - "requires": { - "reusify": "^1.0.0" - } - }, "fb-watchman": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", @@ -5412,17 +5206,6 @@ } } }, - "find-my-way": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-1.17.0.tgz", - "integrity": "sha512-V/ROUAESJakNZXmvgJmaCwhB8d4M79/RgWWiKn4tu/6FGjiySYfJuYXip1rV7fORWEzbL0pmfg9smkRQ+tmXjg==", - "dev": true, - "requires": { - "fast-decode-uri-component": "^1.0.0", - "safe-regex": "^1.1.0", - "semver-store": "^0.3.0" - } - }, "find-npm-prefix": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz", @@ -5444,12 +5227,6 @@ "locate-path": "^3.0.0" } }, - "flatstr": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.9.tgz", - "integrity": "sha512-qFlJnOBWDfIaunF54/lBqNKmXOI0HqNhu+mHkLmbaBXlS71PUd9OjFOdyevHt/aHoHB1+eW7eKHgRKOG5aHSpw==", - "dev": true - }, "flush-write-stream": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", @@ -5673,8 +5450,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -5698,15 +5474,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5723,22 +5497,19 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -5869,8 +5640,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -5884,7 +5654,6 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5901,7 +5670,6 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5910,15 +5678,13 @@ "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.4.tgz", "integrity": "sha512-hzXIWWet/BzWhYs2b+u7dRHlruXhwdgvlTMDKC6Cb1U7ps6Ac6yQlR39xsbjWJE377YTCtKwIXIpJ5oP+j5y8g==", "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -5939,7 +5705,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -6028,8 +5793,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -6043,7 +5807,6 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -6139,8 +5902,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -6182,7 +5944,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -6204,7 +5965,6 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -6253,15 +6013,13 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", - "dev": true, - "optional": true + "dev": true } } }, @@ -9110,62 +8868,6 @@ } } }, - "light-my-request": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-3.1.0.tgz", - "integrity": "sha512-ZSFO3XnQNSKsHR/E2ZMga5btdiIa3sNoT6CZIZ8Hr1VHJWBNcRRurVYpQlaJqvQqwg3aOl09QpVOnjB9ajnYHQ==", - "dev": true, - "requires": { - "ajv": "^6.0.0", - "readable-stream": "^3.0.0" - }, - "dependencies": { - "ajv": { - "version": "6.6.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.6.2.tgz", - "integrity": "sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "readable-stream": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.1.1.tgz", - "integrity": "sha512-DkN66hPyqDhnIQ6Jcsvx9bFjhw214O4poMBcIMgPVpQvNy9a0e0Uhg5SqySyDKAmUlwt8LonTBz1ezOnM8pUdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "string_decoder": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", - "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, "lint-staged": { "version": "8.1.3", "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-8.1.3.tgz", @@ -10186,24 +9888,6 @@ "regex-cache": "^0.4.2" } }, - "middie": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/middie/-/middie-3.2.0.tgz", - "integrity": "sha512-anXJ0QJfQcgneQvcWAJBwVvNckRLI68zWNEUv/7/7z/Wb/UMFTHmugpM93T4Q75+DclC9FHdms8cTseDQEV3yA==", - "dev": true, - "requires": { - "path-to-regexp": "^2.0.0", - "reusify": "^1.0.2" - }, - "dependencies": { - "path-to-regexp": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-2.4.0.tgz", - "integrity": "sha512-G6zHoVqC6GGTQkZwF4lkuEyMbVOjoBKAEybQUypI1WTkqinCOrq2x6U2+phkJ1XsEMTy4LjtwPI7HW+NVrRR2w==", - "dev": true - } - } - }, "mime": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", @@ -11253,41 +10937,6 @@ "pinkie": "^2.0.0" } }, - "pino": { - "version": "4.17.6", - "resolved": "https://registry.npmjs.org/pino/-/pino-4.17.6.tgz", - "integrity": "sha512-LFDwmhyWLBnmwO/2UFbWu1jEGVDzaPupaVdx0XcZ3tIAx1EDEBauzxXf2S0UcFK7oe+X9MApjH0hx9U1XMgfCA==", - "dev": true, - "requires": { - "chalk": "^2.4.1", - "fast-json-parse": "^1.0.3", - "fast-safe-stringify": "^1.2.3", - "flatstr": "^1.0.5", - "pino-std-serializers": "^2.0.0", - "pump": "^3.0.0", - "quick-format-unescaped": "^1.1.2", - "split2": "^2.2.0" - }, - "dependencies": { - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - } - } - }, - "pino-std-serializers": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-2.3.0.tgz", - "integrity": "sha512-klfGoOsP6sJH7ON796G4xoUSx2fkpFgKHO4YVVO2zmz31jR+etzc/QzGJILaOIiCD6HTCFgkPx+XN8nk+ruqPw==", - "dev": true - }, "pkg-dir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", @@ -11571,15 +11220,6 @@ } } }, - "quick-format-unescaped": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-1.1.2.tgz", - "integrity": "sha1-DKWB3jF0vs7yWsPC6JVjQjgdtpg=", - "dev": true, - "requires": { - "fast-safe-stringify": "^1.0.8" - } - }, "quick-lru": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-1.1.0.tgz", @@ -11972,12 +11612,6 @@ "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", @@ -12353,7 +11987,8 @@ "semver": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", - "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true }, "semver-compare": { "version": "1.0.0", @@ -12361,12 +11996,6 @@ "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", "dev": true }, - "semver-store": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/semver-store/-/semver-store-0.3.0.tgz", - "integrity": "sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg==", - "dev": true - }, "send": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", @@ -13191,12 +12820,6 @@ } } }, - "tiny-lru": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-1.6.4.tgz", - "integrity": "sha512-Et+J3Css66XPSLWjLF9wmgbECsGiExlEL+jxsFerTQF6N6dpxswDTPAfIrAbQKO5c1uhgq2xvo5zMk1W+kBDNA==", - "dev": true - }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -13598,23 +13221,6 @@ } } }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - } - } - }, "urijs": { "version": "1.19.1", "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.1.tgz", diff --git a/package.json b/package.json index 26f0e3bd41f..443d9a554cd 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,6 @@ "apollo-server-env": "file:packages/apollo-server-env", "apollo-server-errors": "file:packages/apollo-server-errors", "apollo-server-express": "file:packages/apollo-server-express", - "apollo-server-fastify": "file:packages/apollo-server-fastify", "apollo-server-hapi": "file:packages/apollo-server-hapi", "apollo-server-integration-testsuite": "file:packages/apollo-server-integration-testsuite", "apollo-server-koa": "file:packages/apollo-server-koa", @@ -97,7 +96,6 @@ "codecov": "3.1.0", "connect": "3.6.6", "express": "4.16.4", - "fastify": "1.13.0", "fibers": "3.1.1", "form-data": "2.3.3", "graphql": "14.1.1", diff --git a/packages/apollo-server-fastify/.npmignore b/packages/apollo-server-fastify/.npmignore deleted file mode 100644 index a165046d359..00000000000 --- a/packages/apollo-server-fastify/.npmignore +++ /dev/null @@ -1,6 +0,0 @@ -* -!src/**/* -!dist/**/* -dist/**/*.test.* -!package.json -!README.md diff --git a/packages/apollo-server-fastify/README.md b/packages/apollo-server-fastify/README.md deleted file mode 100644 index 39a322c49af..00000000000 --- a/packages/apollo-server-fastify/README.md +++ /dev/null @@ -1,41 +0,0 @@ ---- -title: Fastify -description: Setting up Apollo Server with Fastify ---- - -[![npm version](https://badge.fury.io/js/apollo-server-fastify.svg)](https://badge.fury.io/js/apollo-server-fastify) [![Build Status](https://circleci.com/gh/apollographql/apollo-server.svg?style=svg)](https://circleci.com/gh/apollographql/apollo-server) [![Coverage Status](https://coveralls.io/repos/github/apollographql/apollo-server/badge.svg?branch=master)](https://coveralls.io/github/apollographql/apollo-server?branch=master) [![Get on Slack](https://img.shields.io/badge/slack-join-orange.svg)](https://www.apollographql.com/#slack) - -This is the Fastify integration of GraphQL Server. Apollo Server is a community-maintained open-source GraphQL server that works with many Node.js HTTP server frameworks. [Read the docs](https://www.apollographql.com/docs/apollo-server/). [Read the CHANGELOG.](https://github.com/apollographql/apollo-server/blob/master/CHANGELOG.md) - -```sh -npm install apollo-server-fastify -``` - -## Fastify - -```js -const { ApolloServer, gql } = require('apollo-server-fastify'); -const { typeDefs, resolvers } = require('./module'); - -const server = new ApolloServer({ - typeDefs, - resolvers, -}); - -const app = require('fastify')(); - -(async function () { - app.register(server.createHandler()); - await app.listen(3000); -})(); -``` - -## Principles - -GraphQL Server is built with the following principles in mind: - -* **By the community, for the community**: GraphQL Server's development is driven by the needs of developers -* **Simplicity**: by keeping things simple, GraphQL Server is easier to use, easier to contribute to, and more secure -* **Performance**: GraphQL Server is well-tested and production-ready - no modifications needed - -Anyone is welcome to contribute to GraphQL Server, just read [CONTRIBUTING.md](https://github.com/apollographql/apollo-server/blob/master/CONTRIBUTING.md), take a look at the [roadmap](https://github.com/apollographql/apollo-server/blob/master/ROADMAP.md) and make your first PR! diff --git a/packages/apollo-server-fastify/jest.config.js b/packages/apollo-server-fastify/jest.config.js deleted file mode 100644 index a383fbc925f..00000000000 --- a/packages/apollo-server-fastify/jest.config.js +++ /dev/null @@ -1,3 +0,0 @@ -const config = require('../../jest.config.base'); - -module.exports = Object.assign(Object.create(null), config); diff --git a/packages/apollo-server-fastify/package.json b/packages/apollo-server-fastify/package.json deleted file mode 100644 index 00c470990d3..00000000000 --- a/packages/apollo-server-fastify/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "apollo-server-fastify", - "version": "2.4.0-alpha.3", - "description": "Production-ready Node.js GraphQL server for Fastify", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "repository": { - "type": "git", - "url": "https://github.com/apollographql/apollo-server/tree/master/packages/apollo-server-fastify" - }, - "keywords": [ - "GraphQL", - "Apollo", - "Server", - "Fastify", - "Javascript" - ], - "author": "opensource@apollographql.com", - "license": "MIT", - "bugs": { - "url": "https://github.com/apollographql/apollo-server/issues" - }, - "homepage": "https://github.com/apollographql/apollo-server#readme", - "engines": { - "node": ">=6" - }, - "dependencies": { - "@apollographql/graphql-playground-html": "^1.6.6", - "apollo-server-core": "file:../apollo-server-core", - "fastify-accepts": "^0.5.0", - "fastify-cors": "^0.2.0", - "graphql-subscriptions": "^1.0.0", - "graphql-tools": "^4.0.0" - }, - "devDependencies": { - "apollo-server-integration-testsuite": "file:../apollo-server-integration-testsuite" - }, - "peerDependencies": { - "graphql": "^0.12.0 || ^0.13.0 || ^14.0.0" - } -} diff --git a/packages/apollo-server-fastify/src/ApolloServer.ts b/packages/apollo-server-fastify/src/ApolloServer.ts deleted file mode 100644 index d8a6f73d50c..00000000000 --- a/packages/apollo-server-fastify/src/ApolloServer.ts +++ /dev/null @@ -1,191 +0,0 @@ -import { renderPlaygroundPage } from '@apollographql/graphql-playground-html'; -import { Accepts } from 'accepts'; -import { - ApolloServerBase, - FileUploadOptions, - formatApolloErrors, - PlaygroundRenderPageOptions, - processFileUploads, -} from 'apollo-server-core'; -import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'; -import { IncomingMessage, OutgoingMessage, Server } from 'http'; -import { graphqlFastify } from './fastifyApollo'; - -const kMultipart = Symbol('multipart'); -const fastJson = require('fast-json-stringify'); - -export interface ServerRegistration { - path?: string; - cors?: object | boolean; - onHealthCheck?: (req: FastifyRequest) => Promise; - disableHealthCheck?: boolean; -} - -const stringifyHealthCheck = fastJson({ - type: 'object', - properties: { - status: { - type: 'string', - }, - }, -}); - -const fileUploadMiddleware = ( - uploadsConfig: FileUploadOptions, - server: ApolloServerBase, -) => ( - req: FastifyRequest, - reply: FastifyReply, - done: (err: Error | null, body?: any) => void, -) => { - if ( - (req.req as any)[kMultipart] && - typeof processFileUploads === 'function' - ) { - processFileUploads(req.req, reply.res, uploadsConfig) - .then(body => { - req.body = body; - done(null); - }) - .catch(error => { - if (error.status && error.expose) reply.status(error.status); - - throw formatApolloErrors([error], { - formatter: server.requestOptions.formatError, - debug: server.requestOptions.debug, - }); - }); - } else { - done(null); - } -}; - -export class ApolloServer extends ApolloServerBase { - protected supportsSubscriptions(): boolean { - return true; - } - - protected supportsUploads(): boolean { - return true; - } - - public createHandler({ - path, - cors, - disableHealthCheck, - onHealthCheck, - }: ServerRegistration = {}) { - this.graphqlPath = path ? path : '/graphql'; - const promiseWillStart = this.willStart(); - - return async ( - app: FastifyInstance, - ) => { - await promiseWillStart; - - if (!disableHealthCheck) { - app.get('/.well-known/apollo/server-health', async (req, res) => { - // Response follows https://tools.ietf.org/html/draft-inadarei-api-health-check-01 - res.type('application/health+json'); - - if (onHealthCheck) { - try { - await onHealthCheck(req); - res.send(stringifyHealthCheck({ status: 'pass' })); - } catch (e) { - res.status(503).send(stringifyHealthCheck({ status: 'fail' })); - } - } else { - res.send(stringifyHealthCheck({ status: 'pass' })); - } - }); - } - - app.register( - async instance => { - instance.register(require('fastify-accepts')); - - if (cors === true) { - instance.register(require('fastify-cors')); - } else if (cors !== false) { - instance.register(require('fastify-cors'), cors); - } - - instance.setNotFoundHandler((_request, reply) => { - reply.code(405); - reply.header('allow', 'GET, POST'); - reply.send(); - }); - - const beforeHandlers = [ - ( - req: FastifyRequest, - reply: FastifyReply, - done: () => void, - ) => { - // Note: if you enable playground in production and expect to be able to see your - // schema, you'll need to manually specify `introspection: true` in the - // ApolloServer constructor; by default, the introspection query is only - // enabled in dev. - if (this.playgroundOptions && req.req.method === 'GET') { - // perform more expensive content-type check only if necessary - const accept = (req as any).accepts() as Accepts; - const types = accept.types() as string[]; - const prefersHTML = - types.find( - (x: string) => - x === 'text/html' || x === 'application/json', - ) === 'text/html'; - - if (prefersHTML) { - const playgroundRenderPageOptions: PlaygroundRenderPageOptions = { - endpoint: this.graphqlPath, - subscriptionEndpoint: this.subscriptionsPath, - ...this.playgroundOptions, - }; - reply.type('text/html'); - const playground = renderPlaygroundPage( - playgroundRenderPageOptions, - ); - reply.send(playground); - return; - } - } - done(); - }, - ]; - - if (typeof processFileUploads === 'function' && this.uploadsConfig) { - instance.addContentTypeParser( - 'multipart', - ( - request: IncomingMessage, - done: (err: Error | null, body?: any) => void, - ) => { - (request as any)[kMultipart] = true; - done(null); - }, - ); - beforeHandlers.push(fileUploadMiddleware(this.uploadsConfig, this)); - } - - instance.route({ - method: ['GET', 'POST'], - url: '/', - beforeHandler: beforeHandlers, - handler: await graphqlFastify(this.graphQLServerOptions.bind(this)), - }); - }, - { - prefix: this.graphqlPath, - }, - ); - }; - } -} - -export const registerServer = () => { - throw new Error( - 'Please use server.createHandler instead of registerServer. This warning will be removed in the next release', - ); -}; diff --git a/packages/apollo-server-fastify/src/__tests__/ApolloServer.test.ts b/packages/apollo-server-fastify/src/__tests__/ApolloServer.test.ts deleted file mode 100644 index 356e005e3e1..00000000000 --- a/packages/apollo-server-fastify/src/__tests__/ApolloServer.test.ts +++ /dev/null @@ -1,836 +0,0 @@ -import { FastifyInstance } from 'fastify'; -import fastify from 'fastify'; - -import http from 'http'; - -import request from 'request'; -import FormData from 'form-data'; -import fs from 'fs'; -import { createApolloFetch } from 'apollo-fetch'; - -import { gql, AuthenticationError, Config } from 'apollo-server-core'; -import { ApolloServer, ServerRegistration } from '../ApolloServer'; - -import { - NODE_MAJOR_VERSION, - testApolloServer, - createServerInfo, -} from 'apollo-server-integration-testsuite'; - -const typeDefs = gql` - type Query { - hello: String - } -`; - -const resolvers = { - Query: { - hello: () => 'hi', - }, -}; - -const port = 9999; - -describe('apollo-server-fastify', () => { - let server: ApolloServer; - let httpServer: http.Server; - let app: FastifyInstance; - - testApolloServer( - async options => { - server = new ApolloServer(options); - app = fastify(); - app.register(server.createHandler()); - await app.listen(port); - return createServerInfo(server, app.server); - }, - async () => { - if (server) await server.stop(); - if (app) await new Promise(resolve => app.close(() => resolve())); - if (httpServer && httpServer.listening) await httpServer.close(); - }, - ); -}); - -describe('apollo-server-fastify', () => { - let server: ApolloServer; - let app: FastifyInstance; - let httpServer: http.Server; - - async function createServer( - serverOptions: Config, - options: Partial = {}, - ) { - server = new ApolloServer(serverOptions); - app = fastify(); - - app.register(server.createHandler(options)); - await app.listen(port); - - return createServerInfo(server, app.server); - } - - afterEach(async () => { - if (server) await server.stop(); - if (app) await new Promise(resolve => app.close(() => resolve())); - if (httpServer) await httpServer.close(); - }); - - describe('constructor', async () => { - it('accepts typeDefs and resolvers', () => { - return createServer({ typeDefs, resolvers }); - }); - }); - - describe('applyMiddleware', async () => { - it('can be queried', async () => { - const { url: uri } = await createServer({ - typeDefs, - resolvers, - }); - const apolloFetch = createApolloFetch({ uri }); - const result = await apolloFetch({ query: '{hello}' }); - - expect(result.data).toEqual({ hello: 'hi' }); - expect(result.errors).toBeUndefined(); - }); - - // XXX Unclear why this would be something somebody would want (vs enabling - // introspection without graphql-playground, which seems reasonable, eg you - // have your own graphql-playground setup with a custom link) - it('can enable playground separately from introspection during production', async () => { - const INTROSPECTION_QUERY = ` - { - __schema { - directives { - name - } - } - } -`; - - const { url: uri } = await createServer({ - typeDefs, - resolvers, - introspection: false, - }); - - const apolloFetch = createApolloFetch({ uri }); - const result = await apolloFetch({ query: INTROSPECTION_QUERY }); - - expect(result.errors.length).toEqual(1); - expect(result.errors[0].extensions.code).toEqual( - 'GRAPHQL_VALIDATION_FAILED', - ); - - return new Promise((resolve, reject) => { - request( - { - url: uri, - method: 'GET', - headers: { - accept: - 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', - }, - }, - (error, response, body) => { - if (error) { - reject(error); - } else { - expect(body).toMatch('GraphQLPlayground'); - expect(response.statusCode).toEqual(200); - resolve(); - } - }, - ); - }); - }); - - it('renders GraphQL playground by default when browser requests', async () => { - const nodeEnv = process.env.NODE_ENV; - delete process.env.NODE_ENV; - - const { url } = await createServer({ - typeDefs, - resolvers, - }); - - return new Promise((resolve, reject) => { - request( - { - url, - method: 'GET', - headers: { - accept: - 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', - }, - }, - (error, response, body) => { - process.env.NODE_ENV = nodeEnv; - if (error) { - reject(error); - } else { - expect(body).toMatch('GraphQLPlayground'); - expect(body).not.toMatch('settings'); - expect(response.statusCode).toEqual(200); - resolve(); - } - }, - ); - }); - }); - - const playgroundPartialOptionsTest = async () => { - const defaultQuery = 'query { foo { bar } }'; - const endpoint = '/fumanchupacabra'; - const { url } = await createServer( - { - typeDefs, - resolvers, - playground: { - // https://github.com/apollographql/graphql-playground/blob/0e452d2005fcd26f10fbdcc4eed3b2e2af935e3a/packages/graphql-playground-html/src/render-playground-page.ts#L16-L24 - // must be made partial - settings: { - 'editor.theme': 'light', - } as any, - tabs: [ - { - query: defaultQuery, - }, - { - endpoint, - } as any, - ], - }, - }, - {}, - ); - - return new Promise((resolve, reject) => { - request( - { - url, - method: 'GET', - headers: { - accept: - 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', - Folo: 'bar', - }, - }, - (error, response, body) => { - if (error) { - reject(error); - } else { - expect(body).toMatch('GraphQLPlayground'); - expect(body).toMatch(`"editor.theme": "light"`); - expect(body).toMatch(defaultQuery); - expect(body).toMatch(endpoint); - expect(response.statusCode).toEqual(200); - resolve(); - } - }, - ); - }); - }; - - it('accepts partial GraphQL Playground Options in production', async () => { - const nodeEnv = process.env.NODE_ENV; - process.env.NODE_ENV = 'production'; - await playgroundPartialOptionsTest(); - process.env.NODE_ENV = nodeEnv; - }); - - it( - 'accepts partial GraphQL Playground Options when an environment is ' + - 'not specified', - async () => { - const nodeEnv = process.env.NODE_ENV; - delete process.env.NODE_ENV; - await playgroundPartialOptionsTest(); - process.env.NODE_ENV = nodeEnv; - }, - ); - - it('accepts playground options as a boolean', async () => { - const nodeEnv = process.env.NODE_ENV; - delete process.env.NODE_ENV; - - const { url } = await createServer( - { - typeDefs, - resolvers, - playground: false, - }, - {}, - ); - - return new Promise((resolve, reject) => { - request( - { - url, - method: 'GET', - headers: { - accept: - 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', - }, - }, - (error, response, body) => { - process.env.NODE_ENV = nodeEnv; - if (error) { - reject(error); - } else { - expect(body).not.toMatch('GraphQLPlayground'); - expect(response.statusCode).not.toEqual(200); - resolve(); - } - }, - ); - }); - }); - - it('accepts cors configuration', async () => { - const { url: uri } = await createServer( - { - typeDefs, - resolvers, - }, - { - cors: { origin: 'apollographql.com' }, - }, - ); - - const apolloFetch = createApolloFetch({ uri }).useAfter( - (response, next) => { - expect( - response.response.headers.get('access-control-allow-origin'), - ).toEqual('apollographql.com'); - next(); - }, - ); - await apolloFetch({ query: '{hello}' }); - }); - - describe('healthchecks', () => { - afterEach(async () => { - await server.stop(); - }); - - it('creates a healthcheck endpoint', async () => { - const { port } = await createServer({ - typeDefs, - resolvers, - }); - - return new Promise((resolve, reject) => { - request( - { - url: `http://localhost:${port}/.well-known/apollo/server-health`, - method: 'GET', - }, - (error, response, body) => { - if (error) { - reject(error); - } else { - expect(body).toEqual(JSON.stringify({ status: 'pass' })); - expect(response.statusCode).toEqual(200); - resolve(); - } - }, - ); - }); - }); - - it('provides a callback for the healthcheck', async () => { - const { port } = await createServer( - { - typeDefs, - resolvers, - }, - { - onHealthCheck: async () => { - throw Error("can't connect to DB"); - }, - }, - ); - - return new Promise((resolve, reject) => { - request( - { - url: `http://localhost:${port}/.well-known/apollo/server-health`, - method: 'GET', - }, - (error, response, body) => { - if (error) { - reject(error); - } else { - expect(body).toEqual(JSON.stringify({ status: 'fail' })); - expect(response.statusCode).toEqual(503); - resolve(); - } - }, - ); - }); - }); - - it('can disable the healthCheck', async () => { - const { port } = await createServer( - { - typeDefs, - resolvers, - }, - { - disableHealthCheck: true, - }, - ); - - return new Promise((resolve, reject) => { - request( - { - url: `http://localhost:${port}/.well-known/apollo/server-health`, - method: 'GET', - }, - (error, response) => { - if (error) { - reject(error); - } else { - expect(response.statusCode).toEqual(404); - resolve(); - } - }, - ); - }); - }); - }); - // NODE: Skip Node.js 6, but only because `graphql-upload` - // doesn't support it. - (NODE_MAJOR_VERSION === 6 ? describe.skip : describe)( - 'file uploads', - () => { - it('enabled uploads', async () => { - const { port } = await createServer({ - typeDefs: gql` - type File { - filename: String! - mimetype: String! - encoding: String! - } - - type Query { - uploads: [File] - } - - type Mutation { - singleUpload(file: Upload!): File! - } - `, - resolvers: { - Query: { - uploads: () => {}, - }, - Mutation: { - singleUpload: async (_, args) => { - expect((await args.file).stream).toBeDefined(); - return args.file; - }, - }, - }, - }); - - const body = new FormData(); - - body.append( - 'operations', - JSON.stringify({ - query: ` - mutation($file: Upload!) { - singleUpload(file: $file) { - filename - encoding - mimetype - } - } - `, - variables: { - file: null, - }, - }), - ); - - body.append('map', JSON.stringify({ 1: ['variables.file'] })); - body.append('1', fs.createReadStream('package.json')); - - try { - const resolved = await fetch(`http://localhost:${port}/graphql`, { - method: 'POST', - body: body as any, - }); - const text = await resolved.text(); - const response = JSON.parse(text); - - expect(response.data.singleUpload).toEqual({ - filename: 'package.json', - encoding: '7bit', - mimetype: 'application/json', - }); - } catch (error) { - // This error began appearing randomly and seems to be a dev dependency bug. - // https://github.com/jaydenseric/apollo-upload-server/blob/18ecdbc7a1f8b69ad51b4affbd986400033303d4/test.js#L39-L42 - if (error.code !== 'EPIPE') throw error; - } - }); - }, - ); - - describe('errors', () => { - it('returns thrown context error as a valid graphql result', async () => { - const nodeEnv = process.env.NODE_ENV; - delete process.env.NODE_ENV; - const typeDefs = gql` - type Query { - hello: String - } - `; - const resolvers = { - Query: { - hello: () => { - throw Error('never get here'); - }, - }, - }; - const { url: uri } = await createServer({ - typeDefs, - resolvers, - context: () => { - throw new AuthenticationError('valid result'); - }, - }); - - const apolloFetch = createApolloFetch({ uri }); - - const result = await apolloFetch({ query: '{hello}' }); - expect(result.errors.length).toEqual(1); - expect(result.data).toBeUndefined(); - - const e = result.errors[0]; - expect(e.message).toMatch('valid result'); - expect(e.extensions).toBeDefined(); - expect(e.extensions.code).toEqual('UNAUTHENTICATED'); - expect(e.extensions.exception.stacktrace).toBeDefined(); - - process.env.NODE_ENV = nodeEnv; - }); - - it('propogates error codes in dev mode', async () => { - const nodeEnv = process.env.NODE_ENV; - delete process.env.NODE_ENV; - - const { url: uri } = await createServer({ - typeDefs: gql` - type Query { - error: String - } - `, - resolvers: { - Query: { - error: () => { - throw new AuthenticationError('we the best music'); - }, - }, - }, - }); - - const apolloFetch = createApolloFetch({ uri }); - - const result = await apolloFetch({ query: `{error}` }); - expect(result.data).toBeDefined(); - expect(result.data).toEqual({ error: null }); - - expect(result.errors).toBeDefined(); - expect(result.errors.length).toEqual(1); - expect(result.errors[0].extensions.code).toEqual('UNAUTHENTICATED'); - expect(result.errors[0].extensions.exception).toBeDefined(); - expect(result.errors[0].extensions.exception.stacktrace).toBeDefined(); - - process.env.NODE_ENV = nodeEnv; - }); - - it('propogates error codes in production', async () => { - const nodeEnv = process.env.NODE_ENV; - process.env.NODE_ENV = 'production'; - - const { url: uri } = await createServer({ - typeDefs: gql` - type Query { - error: String - } - `, - resolvers: { - Query: { - error: () => { - throw new AuthenticationError('we the best music'); - }, - }, - }, - }); - - const apolloFetch = createApolloFetch({ uri }); - - const result = await apolloFetch({ query: `{error}` }); - expect(result.data).toBeDefined(); - expect(result.data).toEqual({ error: null }); - - expect(result.errors).toBeDefined(); - expect(result.errors.length).toEqual(1); - expect(result.errors[0].extensions.code).toEqual('UNAUTHENTICATED'); - expect(result.errors[0].extensions.exception).toBeUndefined(); - - process.env.NODE_ENV = nodeEnv; - }); - - it('propogates error codes with null response in production', async () => { - const nodeEnv = process.env.NODE_ENV; - process.env.NODE_ENV = 'production'; - - const { url: uri } = await createServer({ - typeDefs: gql` - type Query { - error: String! - } - `, - resolvers: { - Query: { - error: () => { - throw new AuthenticationError('we the best music'); - }, - }, - }, - }); - - const apolloFetch = createApolloFetch({ uri }); - - const result = await apolloFetch({ query: `{error}` }); - expect(result.data).toBeNull(); - - expect(result.errors).toBeDefined(); - expect(result.errors.length).toEqual(1); - expect(result.errors[0].extensions.code).toEqual('UNAUTHENTICATED'); - expect(result.errors[0].extensions.exception).toBeUndefined(); - - process.env.NODE_ENV = nodeEnv; - }); - }); - }); - - describe('extensions', () => { - const books = [ - { - title: 'H', - author: 'J', - }, - ]; - - const typeDefs = gql` - type Book { - title: String - author: String - } - - type Cook @cacheControl(maxAge: 200) { - title: String - author: String - } - - type Pook @cacheControl(maxAge: 200) { - title: String - books: [Book] @cacheControl(maxAge: 20, scope: PRIVATE) - } - - type Query { - books: [Book] - cooks: [Cook] - pooks: [Pook] - } - `; - - const resolvers = { - Query: { - books: () => books, - cooks: () => books, - pooks: () => [{ title: 'pook', books }], - }, - }; - - describe('Cache Control Headers', () => { - it('applies cacheControl Headers and strips out extension', async () => { - const { url: uri } = await createServer({ typeDefs, resolvers }); - - const apolloFetch = createApolloFetch({ uri }).useAfter( - (response, next) => { - expect(response.response.headers.get('cache-control')).toEqual( - 'max-age=200, public', - ); - next(); - }, - ); - const result = await apolloFetch({ - query: `{ cooks { title author } }`, - }); - expect(result.data).toEqual({ cooks: books }); - expect(result.extensions).toBeUndefined(); - }); - - it('contains no cacheControl Headers and keeps extension with engine proxy', async () => { - const { url: uri } = await createServer({ - typeDefs, - resolvers, - cacheControl: true, - }); - - const apolloFetch = createApolloFetch({ uri }).useAfter( - (response, next) => { - expect(response.response.headers.get('cache-control')).toBeNull(); - next(); - }, - ); - const result = await apolloFetch({ - query: `{ cooks { title author } }`, - }); - expect(result.data).toEqual({ cooks: books }); - expect(result.extensions).toBeDefined(); - expect(result.extensions.cacheControl).toBeDefined(); - }); - - it('contains no cacheControl Headers when uncachable', async () => { - const { url: uri } = await createServer({ typeDefs, resolvers }); - - const apolloFetch = createApolloFetch({ uri }).useAfter( - (response, next) => { - expect(response.response.headers.get('cache-control')).toBeNull(); - next(); - }, - ); - const result = await apolloFetch({ - query: `{ books { title author } }`, - }); - expect(result.data).toEqual({ books }); - expect(result.extensions).toBeUndefined(); - }); - - it('contains private cacheControl Headers when scoped', async () => { - const { url: uri } = await createServer({ typeDefs, resolvers }); - - const apolloFetch = createApolloFetch({ uri }).useAfter( - (response, next) => { - expect(response.response.headers.get('cache-control')).toEqual( - 'max-age=20, private', - ); - next(); - }, - ); - const result = await apolloFetch({ - query: `{ pooks { title books { title author } } }`, - }); - expect(result.data).toEqual({ - pooks: [{ title: 'pook', books }], - }); - expect(result.extensions).toBeUndefined(); - }); - - it('runs when cache-control is false', async () => { - const { url: uri } = await createServer({ - typeDefs, - resolvers, - cacheControl: false, - }); - - const apolloFetch = createApolloFetch({ uri }).useAfter( - (response, next) => { - expect(response.response.headers.get('cache-control')).toBeNull(); - next(); - }, - ); - const result = await apolloFetch({ - query: `{ pooks { title books { title author } } }`, - }); - expect(result.data).toEqual({ - pooks: [{ title: 'pook', books }], - }); - expect(result.extensions).toBeUndefined(); - }); - }); - - describe('Tracing', () => { - const typeDefs = gql` - type Book { - title: String - author: String - } - - type Query { - books: [Book] - } - `; - - const resolvers = { - Query: { - books: () => books, - }, - }; - - it('applies tracing extension', async () => { - const { url: uri } = await createServer({ - typeDefs, - resolvers, - tracing: true, - }); - - const apolloFetch = createApolloFetch({ uri }); - const result = await apolloFetch({ - query: `{ books { title author } }`, - }); - expect(result.data).toEqual({ books }); - expect(result.extensions).toBeDefined(); - expect(result.extensions.tracing).toBeDefined(); - }); - - it('applies tracing extension with cache control enabled', async () => { - const { url: uri } = await createServer({ - typeDefs, - resolvers, - tracing: true, - cacheControl: true, - }); - - const apolloFetch = createApolloFetch({ uri }); - const result = await apolloFetch({ - query: `{ books { title author } }`, - }); - expect(result.data).toEqual({ books }); - expect(result.extensions).toBeDefined(); - expect(result.extensions.tracing).toBeDefined(); - }); - - xit('applies tracing extension with engine enabled', async () => { - const { url: uri } = await createServer({ - typeDefs, - resolvers, - tracing: true, - engine: { - apiKey: 'service:my-app:secret', - maxAttempts: 0, - endpointUrl: 'l', - reportErrorFunction: () => {}, - }, - }); - - const apolloFetch = createApolloFetch({ uri }); - const result = await apolloFetch({ - query: `{ books { title author } }`, - }); - expect(result.data).toEqual({ books }); - expect(result.extensions).toBeDefined(); - expect(result.extensions.tracing).toBeDefined(); - }); - }); - }); -}); diff --git a/packages/apollo-server-fastify/src/__tests__/datasource.test.ts b/packages/apollo-server-fastify/src/__tests__/datasource.test.ts deleted file mode 100644 index d7c6d9f5f7d..00000000000 --- a/packages/apollo-server-fastify/src/__tests__/datasource.test.ts +++ /dev/null @@ -1,140 +0,0 @@ -import fastify, { FastifyInstance } from 'fastify'; - -import { RESTDataSource } from 'apollo-datasource-rest'; - -import { createApolloFetch } from 'apollo-fetch'; -import { ApolloServer } from '../ApolloServer'; - -import { createServerInfo } from 'apollo-server-integration-testsuite'; -import { gql } from '../index'; - -const restPort = 4001; - -export class IdAPI extends RESTDataSource { - baseURL = `http://localhost:${restPort}/`; - - async getId(id: string) { - return this.get(`id/${id}`); - } - - async getStringId(id: string) { - return this.get(`str/${id}`); - } -} - -const typeDefs = gql` - type Query { - id: String - stringId: String - } -`; - -const resolvers = { - Query: { - id: async (_source, _args, { dataSources }) => { - return (await dataSources.id.getId('hi')).id; - }, - stringId: async (_source, _args, { dataSources }) => { - return dataSources.id.getStringId('hi'); - }, - }, -}; - -let restCalls = 0; -const restAPI = fastify(); - -restAPI.get('/id/:id', (req, res) => { - const id = req.params.id; - restCalls++; - res.header('Content-Type', 'application/json'); - res.header('Cache-Control', 'max-age=2000, public'); - res.send({ id }); -}); - -restAPI.get('/str/:id', (req, res) => { - const id = req.params.id; - restCalls++; - res.header('Content-Type', 'text/plain'); - res.header('Cache-Control', 'max-age=2000, public'); - res.send(id); -}); - -describe('apollo-server-fastify', () => { - let restServer: FastifyInstance; - let app: FastifyInstance; - - beforeAll(async () => { - await restAPI.listen(restPort); - }); - - afterAll(async () => { - await new Promise(resolve => restServer.close(() => resolve())); - }); - - let server: ApolloServer; - - beforeEach(() => { - restCalls = 0; - }); - - afterEach(async () => { - await server.stop(); - await new Promise(resolve => app.close(() => resolve())); - }); - - it('uses the cache', async () => { - server = new ApolloServer({ - typeDefs, - resolvers, - dataSources: () => ({ - id: new IdAPI(), - }), - }); - app = fastify(); - - app.register(server.createHandler()); - await app.listen(6667); - const { url: uri } = createServerInfo(server, app.server); - - const apolloFetch = createApolloFetch({ uri }); - const firstResult = await apolloFetch({ query: '{ id }' }); - - expect(firstResult.data).toEqual({ id: 'hi' }); - expect(firstResult.errors).toBeUndefined(); - expect(restCalls).toEqual(1); - - const secondResult = await apolloFetch({ query: '{ id }' }); - - expect(secondResult.data).toEqual({ id: 'hi' }); - expect(secondResult.errors).toBeUndefined(); - expect(restCalls).toEqual(1); - }); - - it('can cache a string from the backend', async () => { - server = new ApolloServer({ - typeDefs, - resolvers, - dataSources: () => ({ - id: new IdAPI(), - }), - }); - app = fastify(); - - app.register(server.createHandler()); - await app.listen(6668); - const { url: uri } = createServerInfo(server, app.server); - - const apolloFetch = createApolloFetch({ uri }); - const firstResult = await apolloFetch({ query: '{ id: stringId }' }); - - expect(firstResult.data).toEqual({ id: 'hi' }); - expect(firstResult.errors).toBeUndefined(); - expect(restCalls).toEqual(1); - - const secondResult = await apolloFetch({ query: '{ id: stringId }' }); - - expect(secondResult.data).toEqual({ id: 'hi' }); - expect(secondResult.errors).toBeUndefined(); - expect(restCalls).toEqual(1); - }); -}); diff --git a/packages/apollo-server-fastify/src/__tests__/fastifyApollo.test.ts b/packages/apollo-server-fastify/src/__tests__/fastifyApollo.test.ts deleted file mode 100644 index d81d4d0126b..00000000000 --- a/packages/apollo-server-fastify/src/__tests__/fastifyApollo.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import fastify from 'fastify'; -import { Server } from 'http'; -import { ApolloServer } from '../ApolloServer'; -import testSuite, { - schema as Schema, - CreateAppOptions, -} from 'apollo-server-integration-testsuite'; -import { GraphQLOptions, Config } from 'apollo-server-core'; - -async function createApp(options: CreateAppOptions = {}) { - const app = fastify(); - - const server = new ApolloServer( - (options.graphqlOptions as Config) || { schema: Schema }, - ); - - app.register(server.createHandler()); - await app.listen(); - - return app.server; -} - -async function destroyApp(app: Server) { - if (!app || !app.close) { - return; - } - await new Promise(resolve => app.close(resolve)); -} - -describe('fastifyApollo', () => { - it('throws error if called without schema', function() { - expect(() => new ApolloServer(undefined as GraphQLOptions)).toThrow( - 'ApolloServer requires options.', - ); - }); -}); - -describe('integration:Fastify', () => { - testSuite(createApp, destroyApp); -}); diff --git a/packages/apollo-server-fastify/src/__tests__/tsconfig.json b/packages/apollo-server-fastify/src/__tests__/tsconfig.json deleted file mode 100644 index 86b8a49b265..00000000000 --- a/packages/apollo-server-fastify/src/__tests__/tsconfig.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "../../../../tsconfig.test.base", - "include": ["**/*"], - "references": [ - { "path": "../../" }, - { "path": "../../../apollo-server-integration-testsuite" } - ] -} diff --git a/packages/apollo-server-fastify/src/fastifyApollo.ts b/packages/apollo-server-fastify/src/fastifyApollo.ts deleted file mode 100644 index ee8945a526c..00000000000 --- a/packages/apollo-server-fastify/src/fastifyApollo.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { - convertNodeHttpToRequest, - GraphQLOptions, - runHttpQuery, -} from 'apollo-server-core'; -import { FastifyReply, FastifyRequest, RequestHandler } from 'fastify'; -import { IncomingMessage, OutgoingMessage } from 'http'; - -export async function graphqlFastify( - options: ( - req?: FastifyRequest, - res?: FastifyReply, - ) => GraphQLOptions | Promise, -): Promise> { - if (!options) { - throw new Error('Apollo Server requires options.'); - } - - return async ( - request: FastifyRequest, - reply: FastifyReply, - ) => { - try { - const { graphqlResponse, responseInit } = await runHttpQuery( - [request, reply], - { - method: request.req.method as string, - options, - query: request.req.method === 'POST' ? request.body : request.query, - request: convertNodeHttpToRequest(request.raw), - }, - ); - - if (responseInit.headers) { - for (const [name, value] of Object.entries( - responseInit.headers, - )) { - reply.header(name, value); - } - } - reply.serializer((payload: string) => payload); - reply.send(graphqlResponse); - } catch (error) { - if ('HttpQueryError' !== error.name) { - throw error; - } - - if (error.headers) { - Object.keys(error.headers).forEach(header => { - reply.header(header, error.headers[header]); - }); - } - - reply.code(error.statusCode); - reply.serializer((payload: string) => payload); - reply.send(error.message); - } - }; -} diff --git a/packages/apollo-server-fastify/src/index.ts b/packages/apollo-server-fastify/src/index.ts deleted file mode 100644 index 38374b22e5f..00000000000 --- a/packages/apollo-server-fastify/src/index.ts +++ /dev/null @@ -1,29 +0,0 @@ -export { - GraphQLUpload, - GraphQLOptions, - GraphQLExtension, - Config, - gql, - // Errors - ApolloError, - toApolloError, - SyntaxError, - ValidationError, - AuthenticationError, - ForbiddenError, - UserInputError, - // playground - defaultPlaygroundOptions, - PlaygroundConfig, - PlaygroundRenderPageOptions, -} from 'apollo-server-core'; - -export * from 'graphql-tools'; -export * from 'graphql-subscriptions'; - -// ApolloServer integration. -export { - ApolloServer, - registerServer, - ServerRegistration, -} from './ApolloServer'; diff --git a/packages/apollo-server-fastify/tsconfig.json b/packages/apollo-server-fastify/tsconfig.json deleted file mode 100644 index 71b94f32842..00000000000 --- a/packages/apollo-server-fastify/tsconfig.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "extends": "../../tsconfig.base", - "compilerOptions": { - "rootDir": "./src", - "outDir": "./dist", - }, - "include": ["src/**/*"], - "exclude": ["**/__tests__", "**/__mocks__"], - "references": [ - { "path": "../apollo-server-core" }, - ] -} diff --git a/tsconfig.build.json b/tsconfig.build.json index 9c480033385..ebb88ce4ba9 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -20,7 +20,6 @@ { "path": "./packages/apollo-server-core" }, { "path": "./packages/apollo-server-errors" }, { "path": "./packages/apollo-server-express" }, - { "path": "./packages/apollo-server-fastify" }, { "path": "./packages/apollo-server-hapi" }, { "path": "./packages/apollo-server-koa" }, { "path": "./packages/apollo-server-lambda" }, diff --git a/tsconfig.test.json b/tsconfig.test.json index ff19a6c1965..85f4028c15d 100644 --- a/tsconfig.test.json +++ b/tsconfig.test.json @@ -17,7 +17,6 @@ { "path": "./packages/apollo-server-cloud-functions/src/__tests__/" }, { "path": "./packages/apollo-server-core/src/__tests__/" }, { "path": "./packages/apollo-server-express/src/__tests__/" }, - { "path": "./packages/apollo-server-fastify/src/__tests__/" }, { "path": "./packages/apollo-server-hapi/src/__tests__/" }, { "path": "./packages/apollo-server-koa/src/__tests__/" }, { "path": "./packages/apollo-server-lambda/src/__tests__/" },