graphql: GraphQl Multiple Endpoints not working
Bug Report
Current behavior
When adding multiple endpoints for graphql it gives following weird error
(node:16316) UnhandledPromiseRejectionWarning: Error: Schema must contain uniquely named types but contains multiple types named "User".
at typeMapReducer (C:\Users\arsla\Documents\nest-graphql-practice\node_modules\graphql\type\schema.js:262:13)
at Array.reduce (<anonymous>)
at new GraphQLSchema (C:\Users\arsla\Documents\nest-graphql-practice\node_modules\graphql\type\schema.js:145:28)
at GraphQLSchemaFactory.<anonymous> (C:\Users\arsla\Documents\nest-graphql-practice\node_modules\@nestjs\graphql\dist\schema-builder\graphql-schema.factory.js:28:28)
at Generator.next (<anonymous>)
at C:\Users\arsla\Documents\nest-graphql-practice\node_modules\tslib\tslib.js:113:75
at new Promise (<anonymous>)
at Object.__awaiter (C:\Users\arsla\Documents\nest-graphql-practice\node_modules\tslib\tslib.js:109:16)
at GraphQLSchemaFactory.create (C:\Users\arsla\Documents\nest-graphql-practice\node_modules\@nestjs\graphql\dist\schema-builder\graphql-schema.factory.js:23:24)
at GraphQLSchemaBuilder.<anonymous> (C:\Users\arsla\Documents\nest-graphql-practice\node_modules\@nestjs\graphql\dist\graphql-schema.builder.js:55:56)
(node:16316) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:16316) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Input Code
My appModule look the following
import { Module } from '@nestjs/common';
import { GraphQLModule } from '@nestjs/graphql';
import { MessagesModule } from './messages/messages.module';
import { UserModule } from './user/user.module';
@Module({
imports: [
MessagesModule,
UserModule,
GraphQLModule.forRoot({
autoSchemaFile: 'userSchema.gql',
playground: true,
include: [UserModule],
path: '/user',
}),
GraphQLModule.forRoot({
autoSchemaFile: 'messageSchema.gql',
playground: true,
include: [MessagesModule],
path: '/msg',
})
],
})
export class AppModule { }
Expected behavior
The error above is totally unexpected , I have taken code first approach Also i have tried a lot but didn’t find help any where.
Possible Solution
Environment
Nest version: X.Y.Z
For Tooling issues:
- Node version: v12.6.0
- Platform: Windows
Others:
"@nestjs/common": "^7.0.0",
"@nestjs/core": "^7.0.0",
"@nestjs/graphql": "^7.1.3",
"@nestjs/platform-express": "^7.0.0",
"apollo-server-express": "^2.11.0",
"graphql": "^14.6.0",
"graphql-tools": "^4.0.7",
About this issue
- Original URL
- State: open
- Created 4 years ago
- Reactions: 20
- Comments: 35 (5 by maintainers)
Will do my best to fix this issue as soon as possible
@kamilmysliwiec Have any update for this issue?
@kamilmysliwiec Looking for the fix. Any update?
@kamilmysliwiec thx that would be really nice if its working. My existing api contains about 50 modules with code first approach, I don’t want to update these to schema first.
I decided to switch my code from code first to schema first and now everything works as it should.
I tried the isAbstract: true method, but this still doesn’t work the moment I use any enum, where I can’t set this property. Is this even in progress? Since this is opened since March and it’s still not fixed, maybe it would be a good idea to remove it from the docs as it seems it’s actually supported?
I dug a bit deeper and probably found the culprit for the discrepancy.
During the graphql module initialization and before constructing the schema, the
GraphQLSchemaFactoryresets all storages except of theTypeDefinitionsStorage, which is e. g. referenced by theTypeDefinitionsGenerator(which itself is used byGraphQLSchemaFactory).The second execution of
LazyMetadataStorage.load(resolvers);re-evaluates all object classes and their annotations and therefore cuts references to previous module initializations, but does not clear these references in theTypeDefinitionsStorage, which will be favoured to be re-used later when establishing e. g. connections between field-object-types with their parents.A viable solution is to add a
clearmethod on theTypeDefinitionsGenerator, which in return would call a clear method on theTypeDefinitionsStorage.I will create a PR.
Any chance someone has a solution to solve that while keeping code-first approach ?
I think the multiple endpoint feature in the docs should have a note that it only works with the schema first system until this issue is fixed. I just spent a couple of hours wondering what I’m doing wrong to then decide to google for a possible answer or if someone else ran into the problem I have and this GH issue ended up the #1 result.
I believe this prohibits the ability to have a very secure authentication system with Nest using GraphQL (i.e. refreshing access tokens in a very “tight” cookie path for recalling the refresh token) because one can’t have a separate endpoint for refreshing access tokens.
Also, with the above auth use case in mind, I think it would be cool to have an
excludeprop, (as in opposite to theincludeprop) to tell the GraphqlModule to load every resolver except those noted in theexcludeprop. If that sounds like a feasible idea, I’d even venture to try and PR it and at the same time see if I can dig into the code to find why the endpoint feature isn’t working with the Code First approach.For now and to move forward, I’m going to try creating the separate app suggested above. I’m using a monorepo setup already. Should be easy enough to try. It might not even be a bad idea seeing as a “refresh” endpoint could get a lot of hits with a lot of users and with it being its own app, it would be using a separate process (or even multiple processes) and so, it can scale separate to the core application or rather, not intrude on resources used by the core application.
Scott
@kaufmo Your issue is this https://github.com/kaufmo/nestjs-typeorm-multiple-graphql-bug/blob/684bab8815a001d4be8c9da00c98b7c36590d0d2/src/app.module.ts#L28
Dont use
autoSchema. Removecode-firstapproch totally from the app and createschema.gqlmanually and then give it path totypePathlike this@NormySan I found that when I changed my annotations from
@ObjectType()to@ObjectType({ isAbstract: true })it fixed the issue for me. Not sure if this helps you but thought I’d share.As for my research, as my conflict appears with an
ObjectType, it lies in theTypeDefinitionsGenerator#generateObjectTypeDefs- therefore somewhere in theObjectTypeDefinitionFactoryor one of the underlying registries, where probably the metadata/objects are not cleared and restored between the generation. So references to objects from the first run are reused, which breaks when creating a GraphQLSchema later on.The GraphQLSchema from the official
graphql-jspackage relies on object equality (usingSet#hason GraphQLObjectType instances) and therefore adds referenced ObjectTypes twice - the one referenced in the metadata in the fields from a previous run as well as the object itself from the fresh generation.Either the metadata/registries have to be cleared and constructed from scratch again or all objects have to be reused.
I have not identified the location where some store like a registry is reused from the previous module initialization though.
After some trials and errors I came up with working solution/workaround that allows to keep the code-first approach while having multiple GraphQL endpoints. The solution uses the NestJS workspaces.
The trick is in splitting the project into multiple apps with a shared library. Each of these apps has its own GraphQL configuration and can use whatever models and resolvers from the shared library. As both apps are built separately the schema is generated without any naming conflicts.
Here is the repo with the example
Even one endpoint
is not generating schema at launching tried many paths /src src …/src
@francisfontoura According to the documentation isAbstract is used to suppress SDL generation for the specific object type. If this solves the problem while it’s still added to the schema then it’s most likely a bug since thats not the expected behaviour from my understanding.
I’m not trying to include unused object types in my schema, I’m building an application with multiple GraphQL endpoints and both endpoints are getting the same object types, resolvers etc. added do them even though they are completely seperated and it’s configured to only load object types, resolvers etc. from specific modules.
I’m also having this issue and I really need to get this working. Is there anything that I could help with to get this resolved?
Any updates ? i have tried “code First approach” with different schemas but no luck so far 😦
I’ve created also an example, see #896