Skip to content

Commit

Permalink
feat(fastify) Use createHandler instead of applyMiddleware #626
Browse files Browse the repository at this point in the history
  • Loading branch information
rkorrelboom committed Nov 17, 2018
1 parent 12b00d1 commit 3708a88
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 126 deletions.
2 changes: 1 addition & 1 deletion packages/apollo-server-fastify/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ async function StartServer() {

const app = fastify();

await server.applyMiddleware({
await server.createHandler({
app,
});

Expand Down
111 changes: 55 additions & 56 deletions packages/apollo-server-fastify/src/ApolloServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@ import {
PlaygroundRenderPageOptions,
} from 'apollo-server-core';
import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';
import { IncomingMessage, OutgoingMessage } from 'http';
import { IncomingMessage, OutgoingMessage, Server } 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>;
Expand All @@ -37,61 +36,61 @@ export class ApolloServer extends ApolloServerBase {
return true;
}

public async applyMiddleware({
app,
public async createHandler({
path,
cors,
disableHealthCheck,
onHealthCheck,
}: ServerRegistration) {
}: ServerRegistration = {}) {
this.graphqlPath = path ? path : '/graphql';
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);
return async (
app: FastifyInstance<Server, IncomingMessage, OutgoingMessage>,
) => {
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' }));
} 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();
});
}

app.register(
async instance => {
instance.register(require('fastify-accepts'));

instance.addContentTypeParser(
'multipart',
async (request: IncomingMessage) =>
processFileUploads(request, this.uploadsConfig),
);
if (cors === true) {
instance.register(require('fastify-cors'));
} else if (cors !== false) {
instance.register(require('fastify-cors'), cors);
}

instance.register(graphqlFastify, {
route: {
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.route({
method: ['GET', 'POST'],
url: '/',
beforeHandler: (
req: FastifyRequest<IncomingMessage>,
reply: FastifyReply<OutgoingMessage>,
Expand All @@ -113,7 +112,7 @@ export class ApolloServer extends ApolloServerBase {

if (prefersHTML) {
const playgroundRenderPageOptions: PlaygroundRenderPageOptions = {
endpoint: path,
endpoint: this.graphqlPath,
subscriptionEndpoint: this.subscriptionsPath,
...this.playgroundOptions,
};
Expand All @@ -127,19 +126,19 @@ export class ApolloServer extends ApolloServerBase {
}
done();
},
},
graphqlOptions: this.graphQLServerOptions.bind(this),
});
},
{
prefix: path,
},
);
handler: await graphqlFastify(this.graphQLServerOptions.bind(this)),
});
},
{
prefix: this.graphqlPath,
},
);
};
}
}

export const registerServer = () => {
throw new Error(
'Please use server.applyMiddleware instead of registerServer. This warning will be removed in the next release',
'Please use server.createHandler instead of registerServer. This warning will be removed in the next release',
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe('apollo-server-fastify', () => {
async options => {
server = new ApolloServer(options);
app = fastify();
await server.applyMiddleware({ app });
app.register(await server.createHandler());
await app.listen(port);
return createServerInfo(server, app.server);
},
Expand All @@ -64,7 +64,7 @@ describe('apollo-server-fastify', () => {
server = new ApolloServer(serverOptions);
app = fastify();

await server.applyMiddleware({ ...options, app });
app.register(await server.createHandler(options));
await app.listen(port);

return createServerInfo(server, app.server);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ restAPI.get('/id/:id', (req, res) => {
restCalls++;
res.header('Content-Type', 'application/json');
res.header('Cache-Control', 'max-age=2000, public');
// res.write(JSON.stringify());
res.send({ id });
});

Expand All @@ -57,7 +56,6 @@ restAPI.get('/str/:id', (req, res) => {
restCalls++;
res.header('Content-Type', 'text/plain');
res.header('Cache-Control', 'max-age=2000, public');
// res.write(id);
res.send(id);
});

Expand All @@ -81,7 +79,6 @@ describe('apollo-server-fastify', () => {

afterEach(async () => {
await server.stop();
// await httpServer.close();
await new Promise(resolve => app.close(() => resolve()));
});

Expand All @@ -95,7 +92,7 @@ describe('apollo-server-fastify', () => {
});
app = fastify();

await server.applyMiddleware({ app });
app.register(await server.createHandler());
await app.listen(6667);
const { url: uri } = createServerInfo(server, app.server);

Expand Down Expand Up @@ -123,7 +120,7 @@ describe('apollo-server-fastify', () => {
});
app = fastify();

server.applyMiddleware({ app });
app.register(await server.createHandler());
await app.listen(6668);
const { url: uri } = createServerInfo(server, app.server);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ async function createApp(options: CreateAppOptions = {}) {
const server = new ApolloServer(
(options.graphqlOptions as Config) || { schema: Schema },
);
await server.applyMiddleware({ app });
await app.listen();

(async function() {
app.register(await server.createHandler());
await app.listen();
})();
return app.server;
}

Expand Down
102 changes: 42 additions & 60 deletions packages/apollo-server-fastify/src/fastifyApollo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,75 +3,57 @@ import {
GraphQLOptions,
runHttpQuery,
} from 'apollo-server-core';
import {
FastifyInstance,
FastifyReply,
FastifyRequest,
RegisterOptions,
RouteOptions,
} from 'fastify';
import { IncomingMessage, OutgoingMessage, Server } from 'http';
import { FastifyReply, FastifyRequest, RequestHandler } from 'fastify';
import { IncomingMessage, OutgoingMessage } from 'http';

export interface FastifyGraphQLOptionsFunction
extends RegisterOptions<Server, IncomingMessage, OutgoingMessage> {
route: Partial<RouteOptions<Server, IncomingMessage, OutgoingMessage>>;
graphqlOptions: (
export async function graphqlFastify(
options: (
req?: FastifyRequest<IncomingMessage>,
res?: FastifyReply<OutgoingMessage>,
) => GraphQLOptions | Promise<GraphQLOptions>;
}

export async function graphqlFastify(
fastify: FastifyInstance<Server, IncomingMessage, OutgoingMessage>,
options: FastifyGraphQLOptionsFunction,
): Promise<void> {
) => GraphQLOptions | Promise<GraphQLOptions>,
): Promise<RequestHandler<IncomingMessage, OutgoingMessage>> {
if (!options) {
throw new Error('Apollo Server requires options.');
}

fastify.route({
method: ['GET', 'POST'],
url: '/',
handler: async (
request: FastifyRequest<IncomingMessage>,
reply: FastifyReply<OutgoingMessage>,
) => {
try {
const { graphqlResponse, responseInit } = await runHttpQuery(
[request, reply],
{
method: request.req.method as string,
options: options.graphqlOptions,
query: request.req.method === 'POST' ? request.body : request.query,
request: convertNodeHttpToRequest(request.raw),
},
);
return async (
request: FastifyRequest<IncomingMessage>,
reply: FastifyReply<OutgoingMessage>,
) => {
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<string>(
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]);
});
if (responseInit.headers) {
for (const [name, value] of Object.entries<string>(
responseInit.headers,
)) {
reply.header(name, value);
}
}
reply.serializer((payload: string) => payload);
reply.send(graphqlResponse);
} catch (error) {
if ('HttpQueryError' !== error.name) {
throw error;
}

reply.code(error.statusCode);
reply.serializer((payload: string) => payload);
reply.send(error.message);
if (error.headers) {
Object.keys(error.headers).forEach(header => {
reply.header(header, error.headers[header]);
});
}
},
...options.route,
});

reply.code(error.statusCode);
reply.serializer((payload: string) => payload);
reply.send(error.message);
}
};
}

0 comments on commit 3708a88

Please sign in to comment.