Skip to content

Issue with codegenMercurius Function Triggering fastify-swagger Error #820

@luthfi-hh

Description

@luthfi-hh

I encountered an error with the codegenMercurius function that seems to be causing a problem with fastify-swagger.
When I include the codegenMercurius function in my code, it triggers an error in swagger-ui.
However, upon removing the codegenMercurius function, the fastify-swagger functionality resumes working as expected.
This issue is affecting my workflow, and I would appreciate any insights or solutions to resolve it. Thank you.

Errors:

ERROR (37310): .swagger() must be called after .ready()
Screenshot 2024-02-19 at 17 56 32 Screenshot 2024-02-19 at 17 51 24

My Code (app.ts):

import { join } from 'path';
import FastifyEnv from '@fastify/env';
import FastifyCors from '@fastify/cors';
import FastifyAutoLoad, { AutoloadPluginOptions } from '@fastify/autoload';
import FastifySwagger from '@fastify/swagger';
import FastifySwaggerUI from '@fastify/swagger-ui';
import { FastifyPluginAsync, FastifyReply, FastifyRequest, FastifyServerOptions } from 'fastify';
import Mercurius from 'mercurius';
import { codegenMercurius } from 'mercurius-codegen'
import { resolvers } from './graphql/resolvers';
import { schema } from './graphql/schema';

export interface AppOptions extends FastifyServerOptions, Partial<AutoloadPluginOptions> {
}

// Pass --options via CLI arguments in command to enable these options.
const options: AppOptions = {
}

const buildContext = async (req: FastifyRequest, _reply: FastifyReply) => {
  return {
    authorization: req.headers.authorization
  }
}

type PromiseType<T> = T extends PromiseLike<infer U> ? U : T

declare module 'mercurius' {
  interface MercuriusContext extends PromiseType<ReturnType<typeof buildContext>> { }
}

const app: FastifyPluginAsync<AppOptions> = async (
  fastify,
  opts
): Promise<void> => {
  // This loads the .env file in the root directory.
  void fastify.register(FastifyEnv, {
    dotenv: true,
    schema: {
      type: 'object',
      required: [
        'NODE_ENV',
        'OPENSEARCH_NODE',
        'OPENSEARCH_USER',
        'OPENSEARCH_PASSWORD',
        'MYSQL_HOST',
        'MYSQL_PORT',
        'MYSQL_USER',
        'MYSQL_PASSWORD',
        'MYSQL_DATABASE',
        'MYSQL_CONNECTION_LIMIT',
      ],
    }
  })

  // This loads the CORS plugin.
  void fastify.register(FastifyCors, {
    origin: '*',
    methods: ['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS', 'PATCH'],
  })

  // This loads fastify-swagger plugin.
  void fastify.register(FastifySwagger, {
    swagger: {
      info: {
        title: 'HH Search API',
        description: 'API for HH Search using OpenSearch',
        version: '0.1.0'
      },
      externalDocs: {
        url: 'https://swagger.io',
        description: 'Find more info here'
      },
      host: 'localhost:3003',
      schemes: ['http', 'https'],
      consumes: ['application/json'],
      produces: ['application/json'],
      tags: [
        { name: 'client', description: 'Client related end-points' },
        { name: 'server', description: 'Server related end-points' }
      ],
      definitions: {
        User: {
          type: 'object',
          required: ['id', 'email'],
          properties: {
            id: { type: 'string', format: 'uuid' },
            firstName: { type: 'string' },
            lastName: { type: 'string' },
            email: { type: 'string', format: 'email' }
          }
        }
      },
      securityDefinitions: {
        apiKey: {
          type: 'apiKey',
          name: 'apiKey',
          in: 'header'
        }
      }
    }
  })

  // This loads fastify-swagger-ui plugin.
  void fastify.register(FastifySwaggerUI, {
    routePrefix: '/docs',
    uiConfig: {
      docExpansion: 'full',
      deepLinking: false
    },
    uiHooks: {
      onRequest: function (request: any, reply: any, next: any) { next() },
      preHandler: function (request: any, reply: any, next: any) { next() }
    },
    staticCSP: true,
    transformStaticCSP: (header: any) => header,
    transformSpecification: (swaggerObject: any, request: any, reply: any) => { return swaggerObject },
    transformSpecificationClone: true
  })

  // This loads the mercurius plugin (GraphQL).
  void fastify.register(Mercurius, {
    schema,
    resolvers,
    jit: 1,
    graphiql: 'graphiql',
    context: buildContext
  })
  
  // This code causing fastify-swagger Errror
  codegenMercurius(fastify, {
    targetPath: './src/graphql/generated.ts',
    operationsGlob: './src/graphql/operations/*.gql',
    codegenConfig: {
      loadersCustomParentTypes: {
        Human: 'never',
      },
    },
  }).catch(console.error)

  
  // Do not touch the following lines

  // This loads all plugins defined in plugins
  // those should be support plugins that are reused
  // through your application
  void fastify.register(FastifyAutoLoad, {
    dir: join(__dirname, 'plugins'),
    options: opts
  })

  // This loads all plugins defined in routes
  // define your routes in one of these
  void fastify.register(FastifyAutoLoad, {
    dir: join(__dirname, 'routes'),
    options: opts
  })
};

export default app;
export { app, options }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions