mirror of
https://github.com/vale981/apollo-server
synced 2025-03-19 17:26:40 -04:00
154 lines
4.6 KiB
TypeScript
154 lines
4.6 KiB
TypeScript
import * as hapi from 'hapi';
|
|
import { ApolloServerBase } from 'apollo-server-core';
|
|
import { parseAll } from 'accept';
|
|
import {
|
|
renderPlaygroundPage,
|
|
RenderPageOptions as PlaygroundRenderPageOptions,
|
|
} from '@apollographql/graphql-playground-html';
|
|
import { processRequest as processFileUploads } from 'apollo-upload-server';
|
|
|
|
import { graphqlHapi } from './hapiApollo';
|
|
|
|
export { GraphQLOptions, GraphQLExtension } from 'apollo-server-core';
|
|
import { GraphQLOptions, FileUploadOptions } from 'apollo-server-core';
|
|
|
|
function handleFileUploads(uploadsConfig: FileUploadOptions) {
|
|
return async (request: hapi.Request) => {
|
|
if (request.mime === 'multipart/form-data') {
|
|
Object.defineProperty(request, 'payload', {
|
|
value: await processFileUploads(request, uploadsConfig),
|
|
writable: false,
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
export class ApolloServer extends ApolloServerBase {
|
|
// This translates the arguments from the middleware into graphQL options It
|
|
// provides typings for the integration specific behavior, ideally this would
|
|
// be propagated with a generic to the super class
|
|
async createGraphQLServerOptions(
|
|
request: hapi.Request,
|
|
h: hapi.ResponseToolkit,
|
|
): Promise<GraphQLOptions> {
|
|
return super.graphQLServerOptions({ request, h });
|
|
}
|
|
|
|
protected supportsSubscriptions(): boolean {
|
|
return true;
|
|
}
|
|
|
|
protected supportsUploads(): boolean {
|
|
return true;
|
|
}
|
|
|
|
public async applyMiddleware({
|
|
app,
|
|
cors,
|
|
path,
|
|
disableHealthCheck,
|
|
gui,
|
|
onHealthCheck,
|
|
}: ServerRegistration) {
|
|
if (!path) path = '/graphql';
|
|
|
|
await app.ext({
|
|
type: 'onRequest',
|
|
method: async function(request, h) {
|
|
if (request.path !== path) {
|
|
return h.continue;
|
|
}
|
|
|
|
if (this.uploadsConfig) {
|
|
await handleFileUploads(this.uploadsConfig)(request);
|
|
}
|
|
|
|
// Note: if you enable a gui 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.
|
|
const guiEnabled =
|
|
!!gui || (gui === undefined && process.env.NODE_ENV !== 'production');
|
|
|
|
// enableGUI takes precedence over the server tools setting
|
|
if (guiEnabled && 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,
|
|
};
|
|
|
|
return h
|
|
.response(renderPlaygroundPage(playgroundRenderPageOptions))
|
|
.type('text/html')
|
|
.takeover();
|
|
}
|
|
}
|
|
return h.continue;
|
|
}.bind(this),
|
|
});
|
|
|
|
if (!disableHealthCheck) {
|
|
await app.route({
|
|
method: '*',
|
|
path: '/.well-known/apollo/server-health',
|
|
options: {
|
|
cors: cors !== undefined ? cors : true,
|
|
},
|
|
handler: async function(request, h) {
|
|
if (onHealthCheck) {
|
|
try {
|
|
await onHealthCheck(request);
|
|
} catch {
|
|
const response = h.response({ status: 'fail' });
|
|
response.code(503);
|
|
response.type('application/health+json');
|
|
return response;
|
|
}
|
|
}
|
|
const response = h.response({ status: 'pass' });
|
|
response.type('application/health+json');
|
|
return response;
|
|
},
|
|
});
|
|
}
|
|
|
|
await app.register({
|
|
plugin: graphqlHapi,
|
|
options: {
|
|
path,
|
|
graphqlOptions: this.createGraphQLServerOptions.bind(this),
|
|
route: {
|
|
cors: cors !== undefined ? cors : true,
|
|
},
|
|
},
|
|
});
|
|
|
|
this.graphqlPath = path;
|
|
}
|
|
}
|
|
|
|
export interface ServerRegistration {
|
|
app?: hapi.Server;
|
|
path?: string;
|
|
cors?: boolean | hapi.RouteOptionsCors;
|
|
onHealthCheck?: (request: hapi.Request) => Promise<any>;
|
|
disableHealthCheck?: boolean;
|
|
gui?: 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',
|
|
);
|
|
};
|