//import { ApolloServer } from 'apollo-server-express'; import express, { Request, Response } from 'express'; import cookieParser from 'cookie-parser'; import gatewaySchema from './schemas/gateway-schema'; import { getGraphQLParameters, processRequest, renderGraphiQL, shouldRenderGraphiQL, sendResult } from 'graphql-helix'; import { checkUpdates } from './check-updates'; import { graphqlUploadExpress } from 'graphql-upload-minimal'; import { parse, visit } from 'graphql'; import { isAllowed } from './check-allowed'; let refreshInterval: any; export type ServiceConfig = { name: string; url: string; prefix: string; versionUrl?: string; _version?: string; upload?: { maxFileSize: number; maxFiles: number; }, }; export type Config = { version?: string; reloadInterval?: number; list: ServiceConfig[]; shouldRenderPlayground?: boolean; allowedQueriesAndMutations: string[]; shouldExposeIntrospetion?: boolean; dangerouslyExposeEverything?: boolean; }; export type Options = { config: Config; }; export const init = async (options: Options) => { const config: Config = options.config; if (options.config.shouldExposeIntrospetion) { options.config.allowedQueriesAndMutations.push('__schema'); } const app = express(); let schema: any; const refresh = async () => { const update = await checkUpdates(config); if (update) { process.env.TEST !== 'true' && console.log('RELOAD SCHEMAS'); schema = await gatewaySchema(config); } }; await refresh(); // Check for version updates every 30 seconds // If we find that any remote schema ahs been updated, we will re-generate the stiched schemas refreshInterval = setInterval(refresh, config.reloadInterval || 1000 * 30); app.use(express.json()); app.use('/graphql', graphqlUploadExpress({ maxFileSize: 10000000, maxFiles: 10 }), async (req, res) => { // Create a generic Request object that can be consumed by Graphql Helix's API const request = { body: req.body, headers: req.headers, method: req.method, query: req.query, }; // Determine whether we should render GraphiQL instead of returning an API response if (shouldRenderGraphiQL(request) && config.shouldRenderPlayground) { res.send(renderGraphiQL()); } else { // Extract the Graphql parameters from the request const { operationName, query, variables } = getGraphQLParameters(request); if (!config.dangerouslyExposeEverything) { const allowed = isAllowed(config, query); if (!allowed) { res.status(403); res.send({ errors: [{ message: 'Not allowed' }] }); return; } } // Validate and execute the query const result = await processRequest({ operationName, query, variables, request, schema, contextFactory: () => ({ req, }), }); // processRequest returns one of three types of results depending on how the server should respond // 1) RESPONSE: a regular JSON payload // 2) MULTIPART RESPONSE: a multipart response (when @stream or @defer directives are used) // 3) PUSH: a stream of events to push back down the client for a subscription // The "sendResult" is a NodeJS-only shortcut for handling all possible types of Graphql responses, // See "Advanced Usage" below for more details and customizations available on that layer. sendResult(result, res); } }); app.get('/status', async (req: Request, res: Response) => { res.send({ micCheck: 'testing, testing', name: 'APIG', version: config.version, }); }); return { app, refresh, stop: () => { clearInterval(refreshInterval); } }; };