apollo-server-hapi: initial implementation of apollo-server base class

This commit is contained in:
Evans Hauser 2018-05-10 17:28:06 -07:00
parent 9fa4a8a62b
commit 98ca26a303
No known key found for this signature in database
GPG key ID: 88AF586817F52EEC
4 changed files with 114 additions and 6 deletions

View file

@ -25,12 +25,16 @@
},
"homepage": "https://github.com/apollographql/apollo-server#readme",
"dependencies": {
"apollo-server-core": "^1.3.6",
"accept": "^3.0.2",
"apollo-server-core": "2.0.0-beta.0",
"apollo-server-module-graphiql": "^1.3.4",
"boom": "^7.1.0"
"boom": "^7.1.0",
"graphql-playground-html": "^1.5.6"
},
"devDependencies": {
"@types/graphql": "0.12.7",
"@types/hapi": "^17.0.12",
"@types/node": "^10.0.6",
"apollo-server-integration-testsuite": "^1.3.6",
"hapi": "17.4.0"
},

View file

@ -0,0 +1,86 @@
import * as hapi from 'hapi';
import { createServer, Server as HttpServer } from 'http';
import { ApolloServerBase, EngineLauncherOptions } from 'apollo-server-core';
import { parseAll } from 'accept';
import { renderPlaygroundPage } from 'graphql-playground-html';
import { graphqlHapi } from './hapiApollo';
export interface ServerRegistration {
app: hapi.Server;
server: ApolloServerBase<hapi.Request>;
path?: string;
subscriptions?: boolean;
}
export interface HapiListenOptions {
port?: number | string;
host?: string; // default: ''. This is where engineproxy listens.
pipePath?: string;
graphqlPaths?: string[]; // default: ['/graphql']
innerHost?: string; // default: '127.0.0.1'. This is where Node listens.
launcherOptions?: EngineLauncherOptions;
}
export const registerServer = async ({
app,
server,
path,
}: ServerRegistration) => {
if (!path) path = '/graphql';
await app.ext({
type: 'onRequest',
method: function(request, h) {
if (request.path !== path) {
return h.continue;
}
if (!server.disableTools && request.method === 'get') {
//perform more expensive content-type check only if necessary
const accept = parseAll(request.app);
const types = accept.mediaTypes as string[];
const prefersHTML =
types.find(
(x: string) => x === 'text/html' || x === 'application/json',
) === 'text/html';
if (prefersHTML) {
return h
.response(
renderPlaygroundPage({
subscriptionsEndpoint: server.subscriptions && path,
endpoint: path,
version: '',
}),
)
.type('text/html');
}
}
return h.continue;
},
});
await app.register({
plugin: graphqlHapi,
options: {
path: path,
graphqlOptions: server.request.bind(server),
route: {
cors: true,
},
},
});
server.use({ path, getHttp: () => app.listener });
const listen = server.listen;
server.listen = async options => {
//requires that autoListen is false, so that
//hapi sets up app.listener without start
await app.start();
//starts the hapi listener at a random port when engine proxy used,
//otherwise will start the server at the provided port
return listen({ ...options });
};
};

View file

@ -1,5 +1,5 @@
import * as Boom from 'boom';
import { Server, Response, Request, ReplyNoContinue } from 'hapi';
import { Server, Request } from 'hapi';
import * as GraphiQL from 'apollo-server-module-graphiql';
import {
GraphQLOptions,
@ -39,13 +39,17 @@ const graphqlHapi: IPlugin = {
method: ['GET', 'POST'],
path: options.path || '/graphql',
vhost: options.vhost || undefined,
config: options.route || {},
options: options.route || {},
handler: async (request, h) => {
try {
const gqlResponse = await runHttpQuery([request], {
method: request.method.toUpperCase(),
options: options.graphqlOptions,
query: request.method === 'post' ? request.payload : request.query,
query:
request.method === 'post'
? //TODO type payload as string or Record
(request.payload as any)
: request.query,
});
const response = h.response(gqlResponse);
@ -98,7 +102,7 @@ const graphiqlHapi: IPlugin = {
server.route({
method: 'GET',
path: options.path || '/graphiql',
config: options.route || {},
options: options.route || {},
handler: async (request, h) => {
const graphiqlString = await GraphiQL.resolveGraphiQLString(
request.query,

View file

@ -1,3 +1,14 @@
// Expose types which can be used by both middleware flavors.
export { GraphQLOptions } from 'apollo-server-core';
export {
ApolloError,
toApolloError,
SyntaxError,
ValidationError,
AuthenticationError,
ForbiddenError,
} from 'apollo-server-core';
export {
IRegister,
HapiOptionsFunction,
@ -7,3 +18,6 @@ export {
graphqlHapi,
graphiqlHapi,
} from './hapiApollo';
// ApolloServer integration
export { registerServer } from './ApolloServer';