-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(fastify): Integrate apollo-fastify plugin #626 #1013
Merged
Merged
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
d1f7d96
Integrate apollo-fastify plugin #626
73cd6f2
#626 Fix typescript issues
addityasingh c8ec07e
#626 Update changelog
addityasingh 46b7951
Merge branch 'master' into as-fastify-apollo
addityasingh dc8b4aa
#626 Update README
addityasingh 6ebe74f
Merge branch 'master' into as-fastify-apollo
addityasingh 5169229
#626 Fix the breaking tests
addityasingh 73eb7ac
Merge branch 'master' into as-fastify-apollo
addityasingh e0ae046
Merge branch 'master' into as-fastify-apollo
addityasingh 63e30be
Merge branch 'master' into as-fastify-apollo
addityasingh d1fdf78
Merge branch 'master' into as-fastify-apollo
addityasingh cec04da
Merge branch 'master' into as-fastify-apollo
addityasingh 459594e
Merge branch 'master' into as-fastify-apollo
abernix b48d08a
#626 Fix code review comments
addityasingh e91e015
#626 Run Hapi tests only for node 8 and 9
addityasingh 57589bb
#626 Run Hapi tests only for node 8 and 9
addityasingh 530bce1
#626 Commit package.lock in working state
addityasingh 79a27d1
#626 Use npm instead of yarn for node 4
addityasingh 032220b
Revert package-lock and circle ci test job steps
addityasingh b91b93b
Merge branch 'master' into as-fastify-apollo
addityasingh ad29216
Merge branch 'master' into as-fastify-apollo
addityasingh 3a72e86
Merge branch 'master' into as-fastify-apollo
addityasingh 6a075dc
Merge branch 'master' into as-fastify-apollo
addityasingh 71b2a2f
#626 Bump the version
addityasingh 34f210c
Merge branch 'master' into as-fastify-apollo
addityasingh 5d96da3
Merge branch 'master' into as-fastify-apollo
addityasingh b0b5c7d
Merge branch 'master' into as-fastify-apollo
addityasingh 9b9caf7
Merge branch 'master' into as-fastify-apollo
addityasingh 38208f3
Merge branch 'master' into as-fastify-apollo
addityasingh 8f4920f
Merge branch 'master' into as-fastify-apollo
addityasingh b3ceac8
Merge branch 'master' into as-fastify-apollo
addityasingh f82fd09
Merge branch 'master' into as-fastify-apollo
addityasingh 67fe5e1
Merge branch 'master' into as-fastify-apollo
addityasingh 524e711
Merge branch 'master' into as-fastify-apollo
addityasingh 05ecbc5
Merge branch 'master' into as-fastify-apollo
evans File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
* | ||
!src/**/* | ||
!dist/**/* | ||
dist/**/*.test.* | ||
!package.json | ||
!README.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
--- | ||
title: Fastify | ||
description: Setting up Apollo Server with Fastify | ||
--- | ||
|
||
[![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 all Node.js HTTP server frameworks: Express, Connect, Fastify, Hapi, Koa and Restify. [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 | ||
import fastify from 'fastify'; | ||
import jsonParser from 'fast-json-body'; | ||
import { graphqlFastify } from 'apollo-server-fastify'; | ||
|
||
const myGraphQLSchema = // ... define or import your schema here! | ||
const PORT = 3000; | ||
|
||
const app = fastify(); | ||
|
||
// jsonParser is needed for POST. | ||
app.addContentTypeParser('application/json', function(req, done) { | ||
jsonParser(req, function(err, body) { | ||
done(err, body); | ||
}); | ||
}); | ||
app.register(graphqlFastify, { schema: myGraphQLSchema }); | ||
|
||
try { | ||
await app.listen(3007); | ||
} catch (err) { | ||
app.log.error(err); | ||
process.exit(1); | ||
} | ||
``` | ||
|
||
## 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! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
{ | ||
"name": "apollo-server-fastify", | ||
"version": "1.0.4", | ||
"description": "Production-ready Node.js GraphQL server for fastify", | ||
"main": "dist/index.js", | ||
"scripts": { | ||
"compile": "tsc", | ||
"prepublish": "npm run compile" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/apollographql/apollo-server/tree/master/packages/apollo-server-fastify" | ||
}, | ||
"keywords": [ | ||
"GraphQL", | ||
"Apollo", | ||
"Server", | ||
"Fastify", | ||
"Javascript" | ||
], | ||
"author": "Aditya pratap Singh <adisinghrajput@gmail.com>", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/apollographql/apollo-server/issues" | ||
}, | ||
"homepage": "https://github.com/apollographql/apollo-server#readme", | ||
"dependencies": { | ||
"apollo-server-core": "^1.3.6", | ||
"apollo-server-module-graphiql": "^1.3.4", | ||
"fastify": "1.3.1" | ||
}, | ||
"devDependencies": { | ||
"@types/graphql": "0.12.7", | ||
"apollo-server-integration-testsuite": "^1.3.6", | ||
"fast-json-body": "^1.1.0", | ||
"http2": "^3.3.7" | ||
}, | ||
"typings": "dist/index.d.ts", | ||
"typescript": { | ||
"definition": "dist/index.d.ts" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import * as fastify from 'fastify'; | ||
import { FastifyInstance } from 'fastify'; | ||
const jsonParser = require('fast-json-body'); | ||
import { graphqlFastify, graphiqlFastify } from './fastifyApollo'; | ||
import testSuite, { | ||
schema, | ||
CreateAppOptions, | ||
} from 'apollo-server-integration-testsuite'; | ||
import { expect } from 'chai'; | ||
import { GraphQLOptions } from 'apollo-server-core'; | ||
import 'mocha'; | ||
|
||
async function createApp(options: CreateAppOptions = {}) { | ||
const app = fastify(); | ||
const graphqlOptions = options.graphqlOptions || { schema }; | ||
|
||
if (!options.excludeParser) { | ||
// @ts-ignore: Dynamic addContentTypeParser error | ||
app.addContentTypeParser('application/json', function(req, done) { | ||
jsonParser(req, function(err, body) { | ||
done(err, body); | ||
}); | ||
}); | ||
} | ||
|
||
if (options.graphiqlOptions) { | ||
app.register(graphiqlFastify, options.graphiqlOptions); | ||
} | ||
app.register(graphqlFastify, { graphqlOptions }); | ||
|
||
try { | ||
await app.listen(3007); | ||
} catch (err) { | ||
app.log.error(err); | ||
process.exit(1); | ||
} | ||
|
||
return app.server; | ||
} | ||
|
||
async function destroyApp(app) { | ||
if (!app || !app.close) { | ||
return; | ||
} | ||
await new Promise(cb => app.close(cb)); | ||
} | ||
|
||
describe('Fastify', () => { | ||
describe('fastifyApollo', () => { | ||
it('throws error if called without schema', function() { | ||
expect(() => | ||
graphqlFastify( | ||
{} as FastifyInstance, | ||
undefined as CreateAppOptions, | ||
undefined, | ||
), | ||
).to.throw('Apollo Server requires options.'); | ||
}); | ||
|
||
it('throws an error if called with argument not equal to 3', function() { | ||
expect(() => (<any>graphqlFastify)({}, { graphqlOptions: {} })).to.throw( | ||
'Apollo Server expects exactly 3 argument, got 2', | ||
); | ||
}); | ||
}); | ||
|
||
describe('integration:Fastify', () => { | ||
testSuite(createApp, destroyApp); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
import * as fastify from 'fastify'; | ||
import { | ||
runHttpQuery, | ||
HttpQueryRequest, | ||
GraphQLOptions, | ||
} from 'apollo-server-core'; | ||
import * as GraphiQL from 'apollo-server-module-graphiql'; | ||
import { | ||
FastifyInstance, | ||
FastifyRequest, | ||
FastifyReply, | ||
Middleware, | ||
} from 'fastify'; | ||
import { IncomingMessage, ServerResponse, Server } from 'http'; | ||
|
||
export function graphqlFastify( | ||
fastify: FastifyInstance, | ||
options: any, | ||
next: (err?: Error) => void, | ||
) { | ||
if (!options || !options.graphqlOptions) { | ||
throw new Error('Apollo Server requires options.'); | ||
} | ||
|
||
if (arguments.length !== 3) { | ||
throw new Error( | ||
`Apollo Server expects exactly 3 argument, got ${arguments.length}`, | ||
); | ||
} | ||
|
||
async function handler<HttpResponse extends ServerResponse>( | ||
request: any, | ||
reply: FastifyReply<HttpResponse>, | ||
) { | ||
const { method } = request.raw; | ||
try { | ||
const gqlResponse = await runHttpQuery([request], { | ||
method: method, | ||
options: options.graphqlOptions, | ||
query: method === 'POST' ? request.body : request.query, | ||
}); | ||
reply | ||
.type('application/json') | ||
.code(200) | ||
.header( | ||
'Content-Length', | ||
Buffer.byteLength(JSON.stringify(gqlResponse), 'utf8'), | ||
) | ||
.send(JSON.parse(gqlResponse)); | ||
} catch (error) { | ||
if ('HttpQueryError' !== error.name) { | ||
return next(error); | ||
} | ||
|
||
if (error.headers) { | ||
Object.keys(error.headers).forEach(header => { | ||
reply.header(header, error.headers[header]); | ||
}); | ||
} | ||
|
||
let errMessage; | ||
try { | ||
errMessage = JSON.parse(error.message); | ||
} catch { | ||
errMessage = error.message; | ||
} | ||
|
||
reply.code(error.statusCode).send(errMessage); | ||
} | ||
} | ||
|
||
fastify.route({ | ||
method: ['GET', 'POST'], | ||
url: options.url || '/graphql', | ||
handler, | ||
}); | ||
|
||
// This is a workaround because of this issue https://github.com/fastify/fastify/pull/862 | ||
fastify.route({ | ||
method: ['HEAD', 'PUT', 'DELETE', 'OPTIONS', 'PATCH'], | ||
url: options.url || '/graphql', | ||
handler: async (req, reply) => { | ||
reply | ||
.code(405) | ||
.header('allow', 'GET, POST') | ||
.send(); | ||
}, | ||
}); | ||
|
||
next(); | ||
return fastify; | ||
} | ||
|
||
export function graphiqlFastify( | ||
fastify: FastifyInstance, | ||
options: any, | ||
next: (err?: Error) => void, | ||
) { | ||
const handler = async (request, reply) => { | ||
try { | ||
const query = request.query; | ||
const giqlResponse = await GraphiQL.resolveGraphiQLString( | ||
query, | ||
options, | ||
request, | ||
); | ||
reply | ||
.header('Content-Type', 'text/html') | ||
.code(200) | ||
.send(giqlResponse); | ||
} catch (error) { | ||
reply.code(500).send(error); | ||
} | ||
}; | ||
|
||
fastify.route({ | ||
method: ['GET', 'POST'], | ||
url: options.url || '/graphiql', | ||
handler, | ||
}); | ||
|
||
// This is a workaround because of this issue https://github.com/fastify/fastify/pull/862 | ||
fastify.route({ | ||
method: ['HEAD', 'PUT', 'DELETE', 'OPTIONS', 'PATCH'], | ||
url: options.url || '/graphiql', | ||
handler: async (req, reply) => { | ||
reply | ||
.code(405) | ||
.header('allow', 'GET, POST') | ||
.send(); | ||
}, | ||
}); | ||
|
||
next(); | ||
return fastify; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
// Expose types which can be used by both middleware flavors. | ||
export { GraphQLOptions } from 'apollo-server-core'; | ||
|
||
// Fastify Middleware | ||
export { graphqlFastify, graphiqlFastify } from './fastifyApollo'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"extends": "../../tsconfig", | ||
"compilerOptions": { | ||
"rootDir": "./src", | ||
"outDir": "./dist", | ||
"typeRoots": ["node_modules/@types"] | ||
}, | ||
"exclude": ["node_modules", "dist"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi! I'm one of the Fastify maintainers :)
Thank you for implementing this!
Just a nit, you don't need to add a content type parse for
application/json
, since it's included directly in Fastify!Besides Fastify performs many security checks that
fast-json-body
is not doing.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@delvedor Thanks a lot for the pointer :) But I implemented this 4 months back and for some reason I had to explicitly add the content parser. But I am working on V2 of this plugin and will take your point into consideration while doing that