UNPKG

traverse-apollo-server-micro

Version:

Production-ready Node.js GraphQL server for Micro

148 lines (129 loc) 3.88 kB
import { ApolloServerBase, GraphQLOptions, processFileUploads, } from 'traverse-apollo-server-core'; import { ServerResponse } from 'http'; import { send } from 'micro'; import { parseAll } from 'accept'; import { graphqlMicro } from './microApollo'; import { MicroRequest } from './types'; export interface ServerRegistration { path?: string; disableHealthCheck?: boolean; onHealthCheck?: (req: MicroRequest) => Promise<any>; } export class ApolloServer extends ApolloServerBase { // Extract Apollo Server options from the request. async createGraphQLServerOptions( req: MicroRequest, res: ServerResponse, ): Promise<GraphQLOptions> { return super.graphQLServerOptions({ req, res }); } // Prepares and returns an async function that can be used by Micro to handle // GraphQL requests. public createHandler({ path, disableHealthCheck, onHealthCheck, }: ServerRegistration = {}) { // We'll kick off the `willStart` right away, so hopefully it'll finish // before the first request comes in. const promiseWillStart = this.willStart(); return async (req, res) => { this.graphqlPath = path || '/graphql'; await promiseWillStart; if (typeof processFileUploads === 'function') { await this.handleFileUploads(req, res); } (await this.handleHealthCheck({ req, res, disableHealthCheck, onHealthCheck, })) || (await this.handleGraphqlRequestsWithServer({ req, res })) || send(res, 404, null); }; } // This integration supports file uploads. protected supportsUploads(): boolean { return true; } // This integration supports subscriptions. protected supportsSubscriptions(): boolean { return true; } // If health checking is enabled, trigger the `onHealthCheck` // function when the health check URL is requested. private async handleHealthCheck({ req, res, disableHealthCheck, onHealthCheck, }: { req: MicroRequest; res: ServerResponse; disableHealthCheck?: boolean; onHealthCheck?: (req: MicroRequest) => Promise<any>; }): Promise<boolean> { let handled = false; if ( !disableHealthCheck && req.url === '/.well-known/apollo/server-health' ) { // Response follows // https://tools.ietf.org/html/draft-inadarei-api-health-check-01 res.setHeader('Content-Type', 'application/health+json'); if (onHealthCheck) { try { await onHealthCheck(req); } catch (error) { send(res, 503, { status: 'fail' }); handled = true; } } if (!handled) { send(res, 200, { status: 'pass' }); handled = true; } } return handled; } // Handle incoming GraphQL requests using Apollo Server. private async handleGraphqlRequestsWithServer({ req, res, }: { req: MicroRequest; res: ServerResponse; }): Promise<boolean> { let handled = false; const url = req.url.split('?')[0]; if (url === this.graphqlPath) { const graphqlHandler = graphqlMicro(() => { return this.createGraphQLServerOptions(req, res); }); const responseData = await graphqlHandler(req, res); send(res, 200, responseData); handled = true; } return handled; } // If file uploads are detected, prepare them for easier handling with // the help of `graphql-upload`. private async handleFileUploads(req: MicroRequest, res: ServerResponse) { if (typeof processFileUploads !== 'function') { return; } const contentType = req.headers['content-type']; if ( this.uploadsConfig && contentType && contentType.startsWith('multipart/form-data') ) { req.filePayload = await processFileUploads(req, res, this.uploadsConfig); } } }