-
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 [WIP] #1760
Closed
addityasingh
wants to merge
20
commits into
apollographql:master
from
addityasingh:as-integrate-fastify-plugin
Closed
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
23b5b32
feat(fastify): Integrate apollo-fastify plugin #626
addityasingh c9bf990
Merge branch 'master' into as-integrate-fastify-plugin
addityasingh f004237
feat(fastify): Fix review comments and broken tests, build #626
addityasingh 69b619b
feat(fastify): Fix test #626
addityasingh aebbcf2
feat(fastify): Remove local package #626
addityasingh dd432e7
feat(fastify): Add fastify package to workspace #626
addityasingh be5907a
Merge branch 'master' into as-integrate-fastify-plugin
addityasingh 4f5509d
feat(fastify): Update package lock #626
addityasingh 55f2975
feat(fastify): Update package lock with latest install #626
addityasingh d78d51a
feat: Update package lock #636
addityasingh a7b5dc7
Merge branch 'master' into as-integrate-fastify-plugin
addityasingh 82afdf2
Merge branch 'master' into as-integrate-fastify-plugin
addityasingh 3d99e3b
Merge branch 'master' into as-integrate-fastify-plugin
addityasingh c4a8b58
feat: Update tsconfig #636
addityasingh 2a74353
feat: Remove overriding tsc compile command #636
addityasingh efb835b
Merge branch 'master' into as-integrate-fastify-plugin
addityasingh 9d22b2f
feat: Add jest config #636
addityasingh 8901556
feat: Fix linting issue#636
addityasingh 2977562
feat: Add tsconfig for fastify tests #636
addityasingh 615a994
Merge branch 'master' into as-integrate-fastify-plugin
addityasingh 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
Large diffs are not rendered by default.
Oops, something went wrong.
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,42 @@ | ||
--- | ||
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 { graphqlFastify } from 'apollo-server-fastify'; | ||
|
||
const myGraphQLSchema = // ... define or import your schema here! | ||
|
||
const app = fastify(); | ||
|
||
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,3 @@ | ||
const config = require('../../jest.config.base'); | ||
|
||
module.exports = Object.assign(Object.create(null), config); |
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,41 @@ | ||
{ | ||
"name": "apollo-server-fastify", | ||
"version": "2.0.0", | ||
"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" | ||
}, | ||
"engines": { | ||
"node": ">=8" | ||
}, | ||
"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": { | ||
"@apollographql/apollo-upload-server": "^5.0.3", | ||
"@apollographql/graphql-playground-html": "^1.6.0", | ||
"apollo-server-core": "file:../apollo-server-core", | ||
"fastify-accepts": "^0.5.0", | ||
"graphql-subscriptions": "^0.5.8", | ||
"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" | ||
} | ||
} |
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,139 @@ | ||
import * as fastify from 'fastify'; | ||
import { FastifyReply } from 'fastify'; | ||
import { FastifyInstance } from 'fastify'; | ||
const { parseAll } = require('fastify-accepts'); | ||
import { | ||
renderPlaygroundPage, | ||
RenderPageOptions as PlaygroundRenderPageOptions, | ||
} from '@apollographql/graphql-playground-html'; | ||
|
||
import { graphqlFastify } from './fastifyApollo'; | ||
|
||
export { GraphQLOptions, GraphQLExtension } from 'apollo-server-core'; | ||
import { ApolloServerBase, GraphQLOptions } from 'apollo-server-core'; | ||
import { IncomingMessage, OutgoingMessage } from 'http'; | ||
|
||
export class ApolloServer extends ApolloServerBase { | ||
async createGraphQLServerOptions( | ||
request: fastify.FastifyRequest<IncomingMessage>, | ||
reply: fastify.FastifyReply<OutgoingMessage>, | ||
): Promise<GraphQLOptions> { | ||
return await super.graphQLServerOptions({ request, reply }); | ||
} | ||
|
||
protected supportsSubscriptions(): boolean { | ||
return true; | ||
} | ||
|
||
protected supportsUploads(): boolean { | ||
return true; | ||
} | ||
|
||
public async applyMiddleware({ | ||
app, | ||
cors, | ||
path, | ||
route, | ||
disableHealthCheck, | ||
onHealthCheck, | ||
}: ServerRegistration) { | ||
if (!path) path = '/graphql'; | ||
|
||
await app.addHook( | ||
'preHandler', | ||
function( | ||
this: any, | ||
request: any, | ||
reply: FastifyReply<OutgoingMessage>, | ||
next: any, | ||
) { | ||
if (request.path !== path) { | ||
return next(); | ||
} | ||
|
||
if (this.playgroundOptions && request.method === 'get') { | ||
// perform more expensive content-type check only if necessary | ||
const accept = parseAll(request.headers); | ||
const types = accept.mediaTypes as string[]; | ||
const prefersHTML = | ||
types.find( | ||
(x: string) => x === 'text/html' || x === 'application/json', | ||
) === 'text/html'; | ||
|
||
if (prefersHTML) { | ||
const playgroundRenderPageOptions: PlaygroundRenderPageOptions = { | ||
endpoint: path, | ||
subscriptionEndpoint: this.subscriptionsPath, | ||
version: this.playgroundVersion, | ||
...this.playgroundOptions, | ||
}; | ||
|
||
reply | ||
.type('text/html') | ||
.send(renderPlaygroundPage(playgroundRenderPageOptions)); | ||
} | ||
} | ||
return next(); | ||
}.bind(this), | ||
addityasingh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
); | ||
|
||
if (!disableHealthCheck) { | ||
await app.route({ | ||
method: [ | ||
'HEAD', | ||
'PUT', | ||
'DELETE', | ||
'OPTIONS', | ||
'PATCH', | ||
] as fastify.HTTPMethod[], | ||
url: '/.well-known/apollo/server-health', | ||
handler: async function( | ||
request: any, | ||
reply: FastifyReply<OutgoingMessage>, | ||
) { | ||
if (onHealthCheck) { | ||
try { | ||
await onHealthCheck(request); | ||
} catch { | ||
const response = reply | ||
.send({ status: 'fail' }) | ||
.code(503) | ||
.type('application/health+json'); | ||
return response; | ||
} | ||
} | ||
const response = reply | ||
.send({ status: 'pass' }) | ||
.type('application/health+json'); | ||
return response; | ||
}, | ||
}); | ||
} | ||
|
||
await app.register(graphqlFastify as any, { | ||
url: path, | ||
graphqlOptions: this.createGraphQLServerOptions.bind(this), | ||
route: route || { cors }, | ||
}); | ||
|
||
this.graphqlPath = path; | ||
} | ||
} | ||
|
||
export interface ServerRegistration { | ||
app?: FastifyInstance; | ||
path?: string; | ||
cors?: boolean; | ||
route?: string; | ||
onHealthCheck?: ( | ||
request: fastify.FastifyRequest<IncomingMessage>, | ||
) => Promise<any>; | ||
disableHealthCheck?: boolean; | ||
uploads?: boolean | Record<string, any>; | ||
} | ||
|
||
export const registerServer = () => { | ||
throw new Error( | ||
'Please use server.applyMiddleware instead of registerServer. This warning will be removed in the next release', | ||
); | ||
}; |
58 changes: 58 additions & 0 deletions
58
packages/apollo-server-fastify/src/__tests__/ApolloServer.test.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,58 @@ | ||
import fastify from 'fastify'; | ||
import http from 'http'; | ||
|
||
import { gql, Config } from 'apollo-server-core'; | ||
import { ApolloServer, ServerRegistration } from '../ApolloServer'; | ||
|
||
import { createServerInfo } from 'apollo-server-integration-testsuite'; | ||
|
||
const typeDefs = gql` | ||
type Query { | ||
hello: String | ||
} | ||
`; | ||
|
||
const resolvers = { | ||
Query: { | ||
hello: () => 'hi', | ||
}, | ||
}; | ||
|
||
const port = 6666; | ||
|
||
describe('apollo-server-fastify', () => { | ||
let server: ApolloServer; | ||
|
||
let app: fastify.FastifyInstance; | ||
let httpServer: http.Server; | ||
|
||
async function createServer( | ||
serverOptions: Config, | ||
options: Partial<ServerRegistration> = {}, | ||
) { | ||
server = new ApolloServer(serverOptions); | ||
app = fastify(); | ||
|
||
server.applyMiddleware({ ...options, app }); | ||
addityasingh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
try { | ||
await app.listen(port); | ||
} catch (err) { | ||
app.log.error('error in starting server', err); | ||
process.exit(1); | ||
} | ||
httpServer = await app.server; | ||
return createServerInfo(server, httpServer); | ||
} | ||
|
||
afterEach(async () => { | ||
if (server) await server.stop(); | ||
if (httpServer) await httpServer.close(); | ||
}); | ||
|
||
describe('constructor', () => { | ||
it('accepts typeDefs and resolvers', () => { | ||
return createServer({ typeDefs, resolvers }); | ||
}); | ||
}); | ||
}); |
57 changes: 57 additions & 0 deletions
57
packages/apollo-server-fastify/src/__tests__/fastifyApollo.test.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,57 @@ | ||
import fastify from 'fastify'; | ||
import { FastifyInstance } from 'fastify'; | ||
import { ApolloServer } from '../ApolloServer'; | ||
import { graphqlFastify } from '../fastifyApollo'; | ||
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 }, | ||
); | ||
await server.applyMiddleware({ app }); | ||
|
||
try { | ||
await app.listen(3007); | ||
} catch (err) { | ||
app.log.error('error in starting server', err); | ||
process.exit(1); | ||
} | ||
|
||
return app.server; | ||
} | ||
|
||
async function destroyApp(app: any) { | ||
if (!app || !app.close) { | ||
return; | ||
} | ||
await new Promise(cb => app.close(cb)); | ||
} | ||
|
||
describe('fastifyApollo', () => { | ||
it('throws error if called without schema', function() { | ||
expect(() => | ||
graphqlFastify( | ||
{} as FastifyInstance, | ||
undefined as GraphQLOptions, | ||
undefined, | ||
), | ||
).toThrow('Apollo Server requires options.'); | ||
}); | ||
|
||
it('throws an error if called with argument not equal to 3', function() { | ||
expect(() => (<any>graphqlFastify)({}, { graphqlOptions: {} })).toThrow( | ||
'Apollo Server expects exactly 3 argument, got 2', | ||
); | ||
}); | ||
}); | ||
|
||
// Uncomment this to see the breaking tests | ||
addityasingh marked this conversation as resolved.
Show resolved
Hide resolved
|
||
describe('integration:Fastify', () => { | ||
testSuite(createApp, destroyApp); | ||
}); |
11 changes: 11 additions & 0 deletions
11
packages/apollo-server-fastify/src/__tests__/tsconfig.json
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,11 @@ | ||
{ | ||
"extends": "../../../../tsconfig.test.base", | ||
"include": ["**/*"], | ||
"references": [{ | ||
"path": "../../" | ||
}, | ||
{ | ||
"path": "../../../apollo-server-integration-testsuite" | ||
} | ||
] | ||
} |
Oops, something went wrong.
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.
I would use https://github.com/fastify/fastify-accepts instead.
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.
Done
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.
I don't think this is working right now, the usage is different.
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.
@mcollina I need a
next()
method along withasync/await
but based on the docswe can't use
next()
along withasync/await
. What would be an alternative in this case?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.
Why do you need it?