nestjs / nest

A progressive Node.js framework for building efficient, scalable, and enterprise-grade server-side applications with TypeScript/JavaScript 🚀
https://nestjs.com
MIT License
66.9k stars 7.56k forks source link

Multiple endpoints graphql using Fastify and Mercurius trigger error ' The decorator 'graphql' has already been added! ' #13057

Closed MedAzizSahli closed 7 months ago

MedAzizSahli commented 8 months ago

Is there an existing issue for this?

Current behavior

In order to have multi endpoints ( /user and /system ) using fastify and mercurius. When i define two different GraphQLModule using of course different path i'm facing this error : throw new FST_ERR_DEC_ALREADY_PRESENT(name) ^ FastifyError: The decorator 'graphql' has already been added!

Minimum reproduction code

https://github.com/

Steps to reproduce

graphql.options.ts

import { GqlOptionsFactory } from '@nestjs/graphql'
import { Injectable } from '@nestjs/common'
import { MercuriusDriverConfig } from '@nestjs/mercurius'
import { join } from 'path'

/**
 * Represents the options for configuring GraphQL in the application.
 */
@Injectable()
export class GraphqlOptions implements GqlOptionsFactory {
  /**
   * Creates the GraphQL options.
   * Using typePaths and definitions, the GraphQL schema is generated from the GraphQL schema files.
   * Use autoSchemaFile instead if you want to generate the GraphQL schema from the TypeScript types.
   * @returns A promise that resolves to the Mercurius driver configuration or the Mercurius driver configuration itself.
   */
  createGqlOptions(): Promise<MercuriusDriverConfig> | MercuriusDriverConfig {
    return {
      path: '/user',
      subscription: true,
      graphiql: process.env.NODE_ENV === 'development',
      typePaths: ['./**/user.gql'],
      definitions: {
        path: join(process.cwd(), 'src/user.ts'),
        outputAs: 'class'
      }
    }
  }
}

graphql.options.two.ts

import { GqlOptionsFactory } from '@nestjs/graphql'
import { Injectable } from '@nestjs/common'
import { MercuriusDriverConfig } from '@nestjs/mercurius'
import { join } from 'path'
import {SystemModule} from './system.module.ts'

/**
 * Represents the options for configuring GraphQL in the application.
 */
@Injectable()
export class GraphqlOptionsTwo implements GqlOptionsFactory {
  /**
   * Creates the GraphQL options.
   * Using typePaths and definitions, the GraphQL schema is generated from the GraphQL schema files.
   * Use autoSchemaFile instead if you want to generate the GraphQL schema from the TypeScript types.
   * @returns A promise that resolves to the Mercurius driver configuration or the Mercurius driver configuration itself.
   */
  createGqlOptions(): Promise<MercuriusDriverConfig> | MercuriusDriverConfig {
    return {
      path: '/system',
      include : [SystemModule]
      subscription: true,
      graphiql: process.env.NODE_ENV === 'development',
      typePaths: ['./**/system.gql'],
      definitions: {
        path: join(process.cwd(), 'src/system.ts'),
        outputAs: 'class'
      }
    }
  }
}

App.Module

import { Module } from '@nestjs/common'
import { TypeOrmModule } from '@nestjs/typeorm'
import { ConfigModule, ConfigService } from '@nestjs/config'
import { AppResolver } from './app.resolver'
import { GraphQLModule } from '@nestjs/graphql'
import { GraphqlOptions } from './graphql.options'
import { GraphqlOptionsTwo } from './graphql.options.Two'
import { MercuriusDriver, MercuriusDriverConfig } from '@nestjs/mercurius'
@Module({
  imports: [
    ConfigModule.forRoot(),

    TypeOrmModule.forRootAsync({
      imports: [ConfigModule],
      inject: [ConfigService],
      useFactory: (config: ConfigService) => ({
        type: 'mysql',
        host: config.get<string>('DATABASE_HOST'),
        port: config.get<number>('DATABASE_PORT'),
        username: config.get<string>('DATABASE_USER'),
        password: config.get<string>('DATABASE_PASSWORD'),
        database: config.get<string>('DATABASE_NAME'),
        autoLoadEntities: true,
        synchronize: false
      })
    }),
    GraphQLModule.forRootAsync<MercuriusDriverConfig>({
      driver: MercuriusDriver,
      useClass: GraphqlOptions
    }),
    GraphQLModule.forRootAsync<MercuriusDriverConfig>({
      driver: MercuriusDriver,
      useClass: GraphqlOptionsTwo
    })
  ],

  providers: [AppResolver]
})
export class AppModule {}

Expected behavior

I want to apply this feature of NestJs link.

Package

Other package

@nestjs/graphql @nestjs/mercurius @nestjs/platform-fastify

NestJS version

10.2.1

Packages versions

{
  "name": "sci_metric_api",
  "version": "0.0.1",
  "description": "",
  "author": "",
  "private": true,
  "license": "UNLICENSED",
  "scripts": {
    "build": "nest build",
    "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
    "start": "nest start",
    "start:dev": "nest start --watch",
    "start:debug": "nest start --debug --watch",
    "start:prod": "node dist/main",
    "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
    "test": "jest",
    "test:unit:ci": "jest --ci",
    "test:watch": "jest --watch",
    "test:cov": "jest --coverage",
    "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
    "test:e2e": "jest --config ./test/jest-e2e.json"
  },
  "dependencies": {
    "@mercuriusjs/gateway": "1.2.0",
    "@nestjs/common": "10.0.0",
    "@nestjs/config": "3.1.1",
    "@nestjs/core": "10.0.0",
    "@nestjs/graphql": "12.0.11",
    "@nestjs/mapped-types": "2.0.4",
    "@nestjs/mercurius": "12.0.11",
    "@nestjs/platform-fastify": "10.2.10",
    "@nestjs/typeorm": "10.0.1",
    "@opentelemetry/instrumentation-fastify": "0.32.5",
    "@opentelemetry/instrumentation-http": "0.45.1",
    "@opentelemetry/instrumentation-nestjs-core": "0.33.3",
    "@opentelemetry/sdk-node": "0.45.1",
    "@opentelemetry/sdk-trace-base": "1.18.1",
    "class-transformer": "0.5.1",
    "class-validator": "0.14.0",
    "graphql": "16.8.1",
    "mercurius": "13.3.1",
    "mysql": "2.18.1",
    "opentelemetry": "0.1.0",
    "pg": "8.11.3",
    "reflect-metadata": "0.1.13",
    "rxjs": "7.8.1",
    "ts-morph": "20.0.0",
    "typeorm": "0.3.17"
  },
  "devDependencies": {
    "@compodoc/compodoc": "1.1.23",
    "@nestjs/cli": "10.0.0",
    "@nestjs/schematics": "10.0.0",
    "@nestjs/testing": "10.0.0",
    "@types/jest": "29.5.2",
    "@types/node": "20.3.1",
    "@types/supertest": "2.0.12",
    "@typescript-eslint/eslint-plugin": "6.0.0",
    "@typescript-eslint/parser": "6.0.0",
    "eslint": "8.42.0",
    "eslint-config-prettier": "9.0.0",
    "eslint-plugin-prettier": "5.0.0",
    "jest": "29.5.0",
    "prettier": "3.0.0",
    "source-map-support": "0.5.21",
    "supertest": "6.3.3",
    "ts-jest": "29.1.0",
    "ts-loader": "9.4.3",
    "ts-node": "10.9.1",
    "tsconfig-paths": "4.2.0",
    "typescript": "5.1.3"
  },
  "jest": {
    "moduleFileExtensions": [
      "js",
      "json",
      "ts"
    ],
    "rootDir": "src",
    "testRegex": ".*\\.spec\\.ts$",
    "transform": {
      "^.+\\.(t|j)s$": "ts-jest"
    },
    "collectCoverageFrom": [
      "**/*.(t|j)s"
    ],
    "coverageDirectory": "../coverage",
    "testEnvironment": "node"
  }
}

Node.js version

20.30.1

In which operating systems have you tested?

Other

No response

wodCZ commented 8 months ago

IMO duplicate of https://github.com/nestjs/graphql/issues/721, Multiple GraphQL endpoints with code-first approach not working is a known issue.

Edit: not a duplicate, but leaving this here as possibly relevant issue.

MedAzizSahli commented 8 months ago

IMO duplicate of nestjs/graphql#721, Multiple GraphQL endpoints with code-first approach not working is a known issue.

Hello I'm using Schema appoach first, also exact same implementation work fine if i use Apollo instead of Mercurius.

ThomasPch commented 8 months ago

Hi, I have the same issue

kamilmysliwiec commented 7 months ago

https://github.com/nestjs/graphql/issues/721