1 | import lambda from 'aws-lambda';
|
2 | import {
|
3 | GraphQLOptions,
|
4 | HttpQueryError,
|
5 | runHttpQuery,
|
6 | } from 'apollo-server-core';
|
7 | import { Headers } from 'apollo-server-env';
|
8 | import { ValueOrPromise } from 'apollo-server-types';
|
9 |
|
10 | export interface LambdaGraphQLOptionsFunction {
|
11 | (event: lambda.APIGatewayProxyEvent, context: lambda.Context): ValueOrPromise<
|
12 | GraphQLOptions
|
13 | >;
|
14 | }
|
15 |
|
16 | export function graphqlLambda(
|
17 | options: GraphQLOptions | LambdaGraphQLOptionsFunction,
|
18 | ): lambda.APIGatewayProxyHandler {
|
19 | if (!options) {
|
20 | throw new Error('Apollo Server requires options.');
|
21 | }
|
22 |
|
23 | if (arguments.length > 1) {
|
24 | throw new Error(
|
25 | `Apollo Server expects exactly one argument, got ${arguments.length}`,
|
26 | );
|
27 | }
|
28 |
|
29 | const graphqlHandler: lambda.APIGatewayProxyHandler = (
|
30 | event,
|
31 | context,
|
32 | callback,
|
33 | ): void => {
|
34 | context.callbackWaitsForEmptyEventLoop = false;
|
35 | let { body, headers, isBase64Encoded } = event;
|
36 | let query: Record<string, any> | Record<string, any>[];
|
37 | const contentType = (
|
38 | headers['content-type'] || headers['Content-Type'] || ''
|
39 | ).toLowerCase();
|
40 | const isMultipart = contentType.startsWith('multipart/form-data');
|
41 |
|
42 | if (body && isBase64Encoded && !isMultipart) {
|
43 | body = Buffer.from(body, 'base64').toString();
|
44 | }
|
45 |
|
46 | if (event.httpMethod === 'POST' && !body) {
|
47 | return callback(null, {
|
48 | body: 'POST body missing.',
|
49 | statusCode: 500,
|
50 | });
|
51 | }
|
52 |
|
53 | if (body && event.httpMethod === 'POST' && isMultipart) {
|
54 | query = body as any;
|
55 | } else if (body && event.httpMethod === 'POST') {
|
56 | query = JSON.parse(body);
|
57 | } else {
|
58 | query = event.queryStringParameters || {};
|
59 | }
|
60 |
|
61 | runHttpQuery([event, context], {
|
62 | method: event.httpMethod,
|
63 | options: options,
|
64 | query,
|
65 | request: {
|
66 | url: event.path,
|
67 | method: event.httpMethod,
|
68 | headers: new Headers(event.headers),
|
69 | },
|
70 | }).then(
|
71 | ({ graphqlResponse, responseInit }) => {
|
72 | callback(null, {
|
73 | body: graphqlResponse,
|
74 | statusCode: 200,
|
75 | headers: responseInit.headers,
|
76 | });
|
77 | },
|
78 | (error: HttpQueryError) => {
|
79 | if ('HttpQueryError' !== error.name) return callback(error);
|
80 | callback(null, {
|
81 | body: error.message,
|
82 | statusCode: error.statusCode,
|
83 | headers: error.headers,
|
84 | });
|
85 | },
|
86 | );
|
87 | };
|
88 |
|
89 | return graphqlHandler;
|
90 | }
|