Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to run multiple GraphQL endpoints in single application #2164

Closed
2 of 4 tasks
kdawgwilk opened this issue May 1, 2022 · 4 comments
Closed
2 of 4 tasks

Unable to run multiple GraphQL endpoints in single application #2164

kdawgwilk opened this issue May 1, 2022 · 4 comments

Comments

@kdawgwilk
Copy link
Contributor

Is there an existing issue for this?

  • I have searched the existing issues

Current behavior

In my app.module.ts I have a GraphQL gateway with a single subgraph

@Module({
  imports: [
    UserModule,
    GraphQLModule.forRoot<ApolloGatewayDriverConfig>({
      driver: ApolloGatewayDriver,
      gateway: {
        supergraphSdl: new IntrospectAndCompose({
          subgraphs: [
            { name: 'users', url: 'http://localhost:3000/users/graphql' },
          ],
        }),
      },
    }),
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

And then I have a users resource with this federated subgraph user.module.ts on the route /users/graphql

@Module({
  imports: [
    GraphQLModule.forRoot<ApolloFederationDriverConfig>({
      driver: ApolloFederationDriver,
      typePaths: ['./**/*.graphql'],
      path: '/users/graphql',
    }),
  ],
  providers: [UserResolver, UserService],
})
export class UserModule {}

The /users/graphql endpoint only works if the gateway is commented out so somehow these two graphql endpoints conflict with each other

Minimum reproduction code

https://github.com/kdawgwilk/nestjs-multiple-graphql-repro

Steps to reproduce

  1. npm I
  2. npm run start:dev
  3. See error
[Nest] 27752  - 04/30/2022, 12:53:37 AM     LOG [NestFactory] Starting Nest application...
[Nest] 27752  - 04/30/2022, 12:53:37 AM     LOG [InstanceLoader] UserModule dependencies initialized +19ms
[Nest] 27752  - 04/30/2022, 12:53:37 AM     LOG [InstanceLoader] AppModule dependencies initialized +1ms
[Nest] 27752  - 04/30/2022, 12:53:37 AM     LOG [InstanceLoader] GraphQLSchemaBuilderModule dependencies initialized +0ms
[Nest] 27752  - 04/30/2022, 12:53:37 AM     LOG [InstanceLoader] GraphQLModule dependencies initialized +0ms
[Nest] 27752  - 04/30/2022, 12:53:37 AM     LOG [InstanceLoader] GraphQLModule dependencies initialized +0ms
[Nest] 27752  - 04/30/2022, 12:53:37 AM     LOG [RoutesResolver] AppController {/}: +8ms
[Nest] 27752  - 04/30/2022, 12:53:37 AM     LOG [RouterExplorer] Mapped {/, GET} route +1ms
Enabling inline tracing for this federated service. To disable, use ApolloServerPluginInlineTraceDisabled.
[Nest] 27752  - 04/30/2022, 12:53:37 AM     LOG [GraphQLModule] Mapped {/users/graphql, POST} route +36ms
Error: Couldn't load service definitions for "users" at http://localhost:3000/users/graphql: request to http://localhost:3000/users/graphql failed, reason: connect ECONNREFUSED 127.0.0.1:3000
    at /Users/kwilk/Sources/pocs/poc-schema/node_modules/@apollo/gateway/src/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.ts:77:15
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at async Promise.all (index 0)
    at loadServicesFromRemoteEndpoint (/Users/kwilk/Sources/pocs/poc-schema/node_modules/@apollo/gateway/src/supergraphManagers/IntrospectAndCompose/loadServicesFromRemoteEndpoint.ts:81:30)
    at IntrospectAndCompose.updateSupergraphSdl (/Users/kwilk/Sources/pocs/poc-schema/node_modules/@apollo/gateway/src/supergraphManagers/IntrospectAndCompose/index.ts:95:20)
    at IntrospectAndCompose.initialize (/Users/kwilk/Sources/pocs/poc-schema/node_modules/@apollo/gateway/src/supergraphManagers/IntrospectAndCompose/index.ts:65:30)
    at ApolloGateway.initializeSupergraphManager (/Users/kwilk/Sources/pocs/poc-schema/node_modules/@apollo/gateway/src/index.ts:462:22)
    at ApolloGateway.load (/Users/kwilk/Sources/pocs/poc-schema/node_modules/@apollo/gateway/src/index.ts:357:7)
    at SchemaManager.start (/Users/kwilk/Sources/pocs/poc-schema/node_modules/apollo-server-core/src/utils/schemaManager.ts:111:22)
    at ApolloServer._start (/Users/kwilk/Sources/pocs/poc-schema/node_modules/apollo-server-core/src/ApolloServer.ts:360:24)

Expected behavior

I would have both graphql endpoints available /graphql for the gateway and /users/graphql for the users subgraph and the gateway would be able to reach the subgraph

Package version

^10.0.10

Graphql version

"@apollo/gateway": "^0.50.2",
"@apollo/subgraph": "^0.4.2",
"apollo-server-express": "^3.6.7",
"graphql": "^16.4.0",

NestJS version

8.4.4

Node.js version

16.14.0

In which operating systems have you tested?

  • macOS
  • Windows
  • Linux

Other

No response

@smolinari
Copy link

@kdawgwilk - I think this is part of a longer running missing feature.

See:

#721
#1999

Scott

@kdawgwilk
Copy link
Contributor Author

kdawgwilk commented May 2, 2022

Yeah I saw #721 but it seemed like that was only for code-first graphql but I have been doing only schema-first but after browsing around more I found #1999 which is basically my exact use case in written test form. I still think it was good to open a new issue since the other main related issues have been locked now. Its still valuable to know when someone else runs into this so we can help show how critical an issue this is so that way it might help get a fix prioritized.

@dimatillck
Copy link

since #721 is locked I post the workaround here.
if different subschemas have ObjectType with the same name it's possible to rename such Objects to allow NestJS to generate the schema and then rename objects back using graphql-tools.

for example, user module can have

@ObjectType('UserModule_User')
export class User {}

and post module can have

@ObjectType('PostModule_User')
export class User {}

Basically, we can use custom ObjectType decorator that supports registerIn argument as described here: #1432 (comment)

The custom decorator can just combine the name of registerIn module with the name of the decorated class and pass the combined name to NestJS ObjectType decorator.

The missing piece is to rename objects back:

import { RenameTypes, wrapSchema } from "@graphql-tools/wrap";

GraphQLModule.forRoot({
  transformSchema(schema: GraphQLSchema) {
    return wrapSchema({
        schema,
        transforms: [
          new RenameTypes((name) => name.replace("UserModule_", "")),
        ],
      })
  }
})

@kamilmysliwiec
Copy link
Member

@nestjs/grapgql wasn't designed to run both gateway and a federated service within a single NestJS application. This isn't currently feasible and there are no plans to support it in the foreseeable future. I'd suggest generating another application within the same repository instead by switching to the NestJS monorepo mode and having 2 apps - one representing a gateway and another one being a federated service.

@nestjs nestjs locked and limited conversation to collaborators May 4, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants