import type Koa from 'koa' ; import type { ParameterizedContext , Middleware } from 'koa' ; import corsMiddleware from '@koa/cors' ; import bodyParser from 'koa-bodyparser' ; import compose from 'koa-compose' ; import { ApolloServerBase , convertNodeHttpToRequest , GraphQLOptions , isHttpQueryError , runHttpQuery , } from 'apollo-server-core' ; import accepts from 'accepts' ; export { GraphQLOptions } from 'apollo-server-core' ; export interface GetMiddlewareOptions { path ? : string ; cors ? : corsMiddleware . Options | boolean ; bodyParserConfig ? : bodyParser . Options | boolean ; onHealthCheck ? : ( ctx : Koa . Context ) => Promise < any > ; disableHealthCheck ? : boolean ; } export interface ServerRegistration extends GetMiddlewareOptions { app : Koa ; } const middlewareFromPath = < StateT , CustomT > ( path , middleware ) => ( ctx , next ) => { if ( ctx . path === path || ctx . path === `${ path }/` ) { return middleware ( ctx , next ) ; } else { return next ( ) ; } } ; export class ApolloServer extends ApolloServerBase { async createGraphQLServerOptions ( ctx ) { return super . graphQLServerOptions ( { ctx } ) ; } public applyMiddleware ( { app , ... rest } ) { this . assertStarted ( 'applyMiddleware' ) ; app . use ( this . getMiddleware ( rest ) ) ; } public getMiddleware ( { path , cors , bodyParserConfig , disableHealthCheck , onHealthCheck , } = { } ) { if ( ! path ) path = '/graphql' ; this . assertStarted ( 'getMiddleware' ) ; const middlewares = [ ] ; if ( ! disableHealthCheck ) { middlewares . push ( middlewareFromPath ( '/.well-known/apollo/server-health' , async ( ctx ) => { ctx . set ( 'Content-Type' , 'application/health+json' ) ; if ( onHealthCheck ) { try { await onHealthCheck ( ctx ) ; ctx . body = { status : 'pass' } ; } catch ( e ) { ctx . status = 503 ; ctx . body = { status : 'fail' } ; } } else { ctx . body = { status : 'pass' } ; } } ) ) ; } this . graphqlPath = path ; if ( cors === true || cors === undefined ) { middlewares . push ( middlewareFromPath ( path , corsMiddleware ( { origin : '*' } ) ) ) ; } else if ( cors !== false ) { middlewares . push ( middlewareFromPath ( path , corsMiddleware ( cors ) ) ) ; } if ( bodyParserConfig === true ) { middlewares . push ( middlewareFromPath ( path , bodyParser ( ) ) ) ; } else if ( bodyParserConfig !== false ) { middlewares . push ( middlewareFromPath ( path , bodyParser ( bodyParserConfig ) ) ) ; } const landingPage = this . getLandingPage ( ) ; middlewares . push ( middlewareFromPath ( path , async ( ctx ) => { if ( ctx . request . method === 'OPTIONS' ) { ctx . status = 204 ; ctx . body = '' ; return ; } if ( landingPage && ctx . request . method === 'GET' ) { const accept = accepts ( ctx . req ) ; const types = accept . types ( ) as string [ ] ; const prefersHtml = types . find ( ( x ) => x === 'text/html' || x === 'application/json' ) === 'text/html' ; if ( prefersHtml ) { ctx . set ( 'Content-Type' , 'text/html' ) ; ctx . body = landingPage . html ; return ; } } try { const { graphqlResponse , responseInit } = await runHttpQuery ( [ ctx ] , { method : ctx . request . method , options : ( ) => this . createGraphQLServerOptions ( ctx ) , query : ctx . request . method === 'POST' ? ( ctx . request as any ) . body || ( ctx . req as any ) . body : ctx . request . query , request : convertNodeHttpToRequest ( ctx . req ) , } ) ; if ( responseInit . headers ) { Object . entries ( responseInit . headers ) . forEach ( ( [ headerName , value ] ) => ctx . set ( headerName , value ) ) ; } ctx . body = graphqlResponse ; ctx . status = responseInit . status || 200 ; } catch ( error ) { if ( ! isHttpQueryError ( error ) ) { throw error ; } if ( error . headers ) { Object . entries ( error . headers ) . forEach ( ( [ headerName , value ] ) => ctx . set ( headerName , value ) ) ; } ctx . status = error . statusCode ; ctx . body = error . message ; } } ) ) ; return compose ( middlewares ) ; } }