UNPKG

@graphql-yoga/nestjs

Version:
137 lines (136 loc) • 5.48 kB
import { __decorate } from "tslib"; import { printSchema } from 'graphql'; import { createYoga, filter, mergeSchemas, pipe, } from 'graphql-yoga'; import { Injectable, Logger } from '@nestjs/common'; import { AbstractGraphQLDriver } from '@nestjs/graphql'; export class AbstractYogaDriver extends AbstractGraphQLDriver { yoga; async start(options) { const platformName = this.httpAdapterHost.httpAdapter.getType(); options = { ...options, // disable error masking by default maskedErrors: options.maskedErrors == null ? false : options.maskedErrors, // disable graphiql in production graphiql: options.graphiql == null ? process.env['NODE_ENV'] !== 'production' : options.graphiql, }; if (platformName === 'express') { return this.registerExpress(options); } if (platformName === 'fastify') { return this.registerFastify(options); } throw new Error(`Provided HttpAdapter "${platformName}" not supported`); } async stop() { // noop } registerExpress({ conditionalSchema, ...options }, { preStartHook } = {}) { const app = this.httpAdapterHost.httpAdapter.getInstance(); preStartHook?.(app); // nest's logger doesnt have the info method class LoggerWithInfo extends Logger { constructor(context) { super(context); } // eslint-disable-next-line @typescript-eslint/no-explicit-any info(message, ...args) { this.log(message, ...args); } } const schema = this.mergeConditionalSchema(conditionalSchema, options.schema); const yoga = createYoga({ ...options, schema, graphqlEndpoint: options.path, // disable logging by default // however, if `true` use nest logger logging: options.logging == null ? false : options.logging ? new LoggerWithInfo('YogaDriver') : options.logging, }); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - TODO: fix types this.yoga = yoga; app.use(yoga.graphqlEndpoint, (req, res) => yoga(req, res, { req, res })); } registerFastify({ conditionalSchema, ...options }, { preStartHook } = {}) { const app = this.httpAdapterHost.httpAdapter.getInstance(); preStartHook?.(app); const schema = this.mergeConditionalSchema(conditionalSchema, options.schema); const yoga = createYoga({ ...options, schema, graphqlEndpoint: options.path, // disable logging by default // however, if `true` use fastify logger logging: options.logging == null ? false : options.logging ? app.log : options.logging, }); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - TODO: fix types this.yoga = yoga; app.all(yoga.graphqlEndpoint, async (req, reply) => { const response = await yoga.handleNodeRequestAndResponse(req, reply, { req, reply, }); for (const [key, value] of response.headers.entries()) reply.header(key, value); reply.status(response.status); reply.send(response.body); return reply; }); } mergeConditionalSchema(conditionalSchema, schema) { let mergedSchema = schema; if (conditionalSchema) { mergedSchema = async (request) => { const schemas = []; if (schema) { schemas.push(schema); } const conditionalSchemaResult = typeof conditionalSchema === 'function' ? await conditionalSchema(request) : await conditionalSchema; if (conditionalSchemaResult) { schemas.push(conditionalSchemaResult); } return mergeSchemas({ schemas, }); }; } return mergedSchema; } subscriptionWithFilter(instanceRef, filterFn, // disable next error, the original function in @nestjs/graphql is also untyped // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type createSubscribeContext) { return async (...args) => { return pipe(await createSubscribeContext()(...args), filter((payload) => // typecast the spread sliced args to avoid error TS 2556, see https://github.com/microsoft/TypeScript/issues/49802 filterFn.call(instanceRef, payload, ...args.slice(1)))); }; } } let YogaDriver = class YogaDriver extends AbstractYogaDriver { subscriptionService; async start(options) { if (options.definitions?.path) { if (!options.schema) { throw new Error('Schema is required when generating definitions'); } await this.graphQlFactory.generateDefinitions(printSchema(options.schema), options); } await super.start(options); } async stop() { await this.subscriptionService?.stop(); } }; YogaDriver = __decorate([ Injectable() ], YogaDriver); export { YogaDriver };