@jaymun723/apollo-server-vercel
Version:
Production-ready Node.js GraphQL server for Vercel Serverless Functions (temporary package).
179 lines (148 loc) • 6.78 kB
JavaScript
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
import { Readable } from "stream";
import { ApolloServerBase, formatApolloErrors } from "apollo-server-core";
import { renderPlaygroundPage } from "@apollographql/graphql-playground-html";
import { Headers } from "node-fetch";
import { processRequest } from "graphql-upload";
import { graphqlVercel } from "./vercelApollo.js";
import { setHeaders } from "./setHeaders.js";
export class FileUploadRequest extends Readable {
constructor(...args) {
super(...args);
_defineProperty(this, "headers", void 0);
}
}
export class ApolloServer extends ApolloServerBase {
createGraphQLServerOptions(req, res) {
return super.graphQLServerOptions({
req,
res
});
}
supportsUploads() {
return true;
}
createHandler({
cors,
onHealthCheck
} = {}) {
const promiseWillStart = this.willStart();
const corsHeaders = new Headers();
if (cors) {
if (cors.methods) {
if (typeof cors.methods === `string`) {
corsHeaders.set(`access-control-allow-methods`, cors.methods);
} else if (Array.isArray(cors.methods)) {
corsHeaders.set(`access-control-allow-methods`, cors.methods.join(`,`));
}
}
if (cors.allowedHeaders) {
if (typeof cors.allowedHeaders === `string`) {
corsHeaders.set(`access-control-allow-headers`, cors.allowedHeaders);
} else if (Array.isArray(cors.allowedHeaders)) {
corsHeaders.set(`access-control-allow-headers`, cors.allowedHeaders.join(`,`));
}
}
if (cors.exposedHeaders) {
if (typeof cors.exposedHeaders === `string`) {
corsHeaders.set(`access-control-expose-headers`, cors.exposedHeaders);
} else if (Array.isArray(cors.exposedHeaders)) {
corsHeaders.set(`access-control-expose-headers`, cors.exposedHeaders.join(`,`));
}
}
if (cors.credentials) {
corsHeaders.set(`access-control-allow-credentials`, `true`);
}
if (typeof cors.maxAge === `number`) {
corsHeaders.set(`access-control-max-age`, cors.maxAge.toString());
}
}
return async (req, res) => {
const requestCorsHeaders = new Headers(corsHeaders);
if (cors && cors.origin) {
const requestOrigin = req.headers.origin;
if (typeof cors.origin === `string`) {
requestCorsHeaders.set(`access-control-allow-origin`, cors.origin);
} else if (requestOrigin && (typeof cors.origin === `boolean` || Array.isArray(cors.origin) && requestOrigin && cors.origin.includes(requestOrigin))) {
requestCorsHeaders.set(`access-control-allow-origin`, requestOrigin);
}
const requestAccessControlRequestHeaders = req.headers[`access-control-request-headers`];
if (!cors.allowedHeaders && requestAccessControlRequestHeaders) {
requestCorsHeaders.set(`access-control-allow-headers`, requestAccessControlRequestHeaders);
}
}
const requestCorsHeadersObject = Array.from(requestCorsHeaders).reduce((headersObject, [key, value]) => {
headersObject[key] = value;
return headersObject;
}, {});
if (req.method === `OPTIONS`) {
setHeaders(res, requestCorsHeadersObject);
return res.status(204).send(``);
}
if (req.url === `/.well-known/apollo/server-health`) {
const successfulResponse = () => {
setHeaders(res, _objectSpread({
"Content-Type": `application/json`
}, requestCorsHeadersObject));
return res.status(200).json({
status: `pass`
});
};
if (onHealthCheck) {
try {
await onHealthCheck(req);
successfulResponse();
} catch {
setHeaders(res, _objectSpread({
"Content-Type": `application/json`
}, requestCorsHeadersObject));
return res.status(503).json({
status: `fail`
});
}
} else {
return successfulResponse();
}
}
if (this.playgroundOptions && req.method === `GET`) {
const acceptHeader = req.headers.Accept || req.headers.accept;
if (acceptHeader && acceptHeader.includes(`text/html`)) {
const path = req.url || `/`;
const playgroundRenderPageOptions = _objectSpread({
endpoint: path
}, this.playgroundOptions);
setHeaders(res, _objectSpread({
"Content-Type": `text/html`
}, requestCorsHeadersObject));
return res.status(200).send(renderPlaygroundPage(playgroundRenderPageOptions));
}
}
const fileUploadHandler = async next => {
const contentType = req.headers[`content-type`] || req.headers[`Content-Type`];
if (contentType && contentType.startsWith(`multipart/form-data`) && typeof processRequest === `function`) {
try {
// req.body = await processFileUploads(req, res, this.uploadsConfig || {});
req.body = await processRequest(req, res, this.uploadsConfig || {});
return next();
} catch (error) {
throw formatApolloErrors([error], {
formatter: this.requestOptions.formatError,
debug: this.requestOptions.debug
});
}
} else {
return next();
}
};
return fileUploadHandler(() => graphqlVercel(async () => {
await promiseWillStart;
if (cors) {
setHeaders(res, _objectSpread({}, requestCorsHeadersObject));
}
return this.createGraphQLServerOptions(req, res);
})(req, res));
};
}
}