Skip to content

Commit

Permalink
feat(fastify) Apollo Fastify server integration resolve #626
Browse files Browse the repository at this point in the history
  • Loading branch information
rkorrelboom committed Jan 2, 2019
1 parent ccd974d commit bacdeae
Show file tree
Hide file tree
Showing 17 changed files with 1,411 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -39,6 +39,7 @@ client reference ID, Apollo Server will now default to the values present in the
of the request (`apollographql-client-name`, `apollographql-client-reference-id` and
`apollographql-client-version` respectively). As a last resort, when those headers are not set,
the query extensions' `clientInfo` values will be used. [PR #1960](https://github.com/apollographql/apollo-server/pull/1960)
- Added `apollo-server-fastify` integration ([@rkorrelboom](https://github.com/rkorrelboom) in [#1971](https://github.com/apollostack/apollo-server/pull/1971))

### v2.2.2

Expand Down
23 changes: 23 additions & 0 deletions README.md
Expand Up @@ -235,6 +235,29 @@ new ApolloServer({
})
```

## Fastify

```js
const { ApolloServer, gql } = require('apollo-server-fastify');
const fastify = require('fastify');

async function StartServer() {
const server = new ApolloServer({ typeDefs, resolvers });

const app = fastify();

await server.applyMiddleware({
app,
});

await server.installSubscriptionHandlers(app.server);

await app.listen(3000);
}

StartServer().catch(error => console.log(error));
```

### 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.
Expand Down
2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -51,6 +51,7 @@
"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",
Expand Down Expand Up @@ -94,6 +95,7 @@
"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.0.2",
Expand Down
6 changes: 6 additions & 0 deletions packages/apollo-server-fastify/.npmignore
@@ -0,0 +1,6 @@
*
!src/**/*
!dist/**/*
dist/**/*.test.*
!package.json
!README.md
45 changes: 45 additions & 0 deletions packages/apollo-server-fastify/README.md
@@ -0,0 +1,45 @@
---
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 fastify = require('fastify');

async function StartServer() {
const server = new ApolloServer({ typeDefs, resolvers });

const app = fastify();

await server.applyMiddleware({
app,
});

await server.installSubscriptionHandlers(app.server);

await app.listen(3000);
}

StartServer().catch(error => console.log(error));
```

## 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!
3 changes: 3 additions & 0 deletions packages/apollo-server-fastify/jest.config.js
@@ -0,0 +1,3 @@
const config = require('../../jest.config.base');

module.exports = Object.assign(Object.create(null), config);
42 changes: 42 additions & 0 deletions packages/apollo-server-fastify/package.json
@@ -0,0 +1,42 @@
{
"name": "apollo-server-fastify",
"version": "2.2.2",
"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/apollo-upload-server": "^5.0.3",
"@apollographql/graphql-playground-html": "^1.6.4",
"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"
}
}
145 changes: 145 additions & 0 deletions packages/apollo-server-fastify/src/ApolloServer.ts
@@ -0,0 +1,145 @@
import { renderPlaygroundPage } from '@apollographql/graphql-playground-html';
import { Accepts } from 'accepts';
import {
ApolloServerBase,
PlaygroundRenderPageOptions,
} from 'apollo-server-core';
import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';
import { IncomingMessage, OutgoingMessage } from 'http';
import { processRequest as processFileUploads } from '@apollographql/apollo-upload-server';
import { graphqlFastify } from './fastifyApollo';

const fastJson = require('fast-json-stringify');

export interface ServerRegistration {
app: FastifyInstance;
path?: string;
cors?: object | boolean;
onHealthCheck?: (req: FastifyRequest<IncomingMessage>) => Promise<any>;
disableHealthCheck?: boolean;
}

const stringifyHealthCheck = fastJson({
type: 'object',
properties: {
status: {
type: 'string',
},
},
});

export class ApolloServer extends ApolloServerBase {
protected supportsSubscriptions(): boolean {
return true;
}

protected supportsUploads(): boolean {
return true;
}

public async applyMiddleware({
app,
path,
cors,
disableHealthCheck,
onHealthCheck,
}: ServerRegistration) {
await this.willStart();

if (!path) path = '/graphql';

this.graphqlPath = path;

app.register(require('fastify-accepts'));

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' }));
}
});
}

if (cors === true) {
app.register(require('fastify-cors'));
} else if (cors !== false) {
app.register(require('fastify-cors'), cors);
}

app.register(
async instance => {
instance.setNotFoundHandler((_request, reply) => {
reply.code(405);
reply.header('allow', 'GET, POST');
reply.send();
});

instance.addContentTypeParser(
'multipart',
async (request: IncomingMessage) =>
processFileUploads(request, this.uploadsConfig),
);

instance.register(graphqlFastify, {
route: {
beforeHandler: (
req: FastifyRequest<IncomingMessage>,
reply: FastifyReply<OutgoingMessage>,
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: path,
subscriptionEndpoint: this.subscriptionsPath,
...this.playgroundOptions,
};
reply.type('text/html');
const playground = renderPlaygroundPage(
playgroundRenderPageOptions,
);
reply.send(playground);
return;
}
}
done();
},
},
graphqlOptions: this.graphQLServerOptions.bind(this),
});
},
{
prefix: path,
},
);
}
}

export const registerServer = () => {
throw new Error(
'Please use server.applyMiddleware instead of registerServer. This warning will be removed in the next release',
);
};

0 comments on commit bacdeae

Please sign in to comment.