Detailed Problem Description for Apollo Federation Gateway with NestJS
Context
I am working on a federated GraphQL setup using Apollo Federation 2 with NestJS. I have a supergraph running on a gateway and two subgraphs. I’m encountering a schema generation issue when configuring one of the subgraphs using forRootAsync
while the gateway fails to introspect and merge the subgraphs.
Supergraph Configuration
The supergraph (gateway) is configured as follows:
const isProd = process.env.ACTIVE_PROFILE == 'production' || process.env.ACTIVE_PROFILE == 'prod';
@Module({
imports: [
GraphQLModule.forRoot<ApolloGatewayDriverConfig>({
driver: ApolloGatewayDriver,
server: {
playground: false,
plugins: isProd ? [] : [ApolloServerPluginLandingPageLocalDefault()],
},
gateway: {
supergraphSdl: new IntrospectAndCompose({
subgraphs: [
{ name: 'hexagon-go', url: 'https://dev.hexagon-graphql.reefos.ai/' },
{ name: 'example', url: 'http://localhost:3000/graphql/' },
],
}),
},
}),
],
})
export class FedGqlModule {}
Subgraph Configuration
The subgraph has two versions of the configuration:
1. Synchronous (Working) Configuration:
@Module({
imports: [
GraphQLModule.forRoot<ApolloFederationDriverConfig>({
driver: ApolloFederationDriver,
autoSchemaFile: {
federation: 2,
},
buildSchemaOptions: {
orphanedTypes: [HexagonExternalUser],
},
plugins: [],
introspection: true,
resolvers: { ID: BigIntIdScalarType },
}),
],
providers: [PostsResolver, PostsService],
})
export class AppModule {}
With this configuration, the schema generates successfully, and the supergraph can introspect and merge it correctly.
2. Asynchronous (Failing) Configuration:
When I switch to forRootAsync
, the schema does not generate, and the gateway fails to compose:
@Module({
imports: [
GraphQLModule.forRootAsync<ApolloFederationDriverConfig>({
driver: ApolloFederationDriver,
useFactory: apolloConfigFactory,
}),
],
providers: [PostsResolver, PostsService],
})
export class AppModule {}
apolloConfigFactory
looks like this:
import { ApolloFederationDriver, ApolloFederationDriverConfig } from '@nestjs/apollo';
import { BigIntIdScalarType } from '../scalars/custom-id.scalar';
const isProd = process.env.ACTIVE_PROFILE === 'production' || process.env.ACTIVE_PROFILE === 'prod';
export const apolloConfigFactory = async () =>
<ApolloFederationDriverConfig>{
cors: {
origin: '*',
credentials: true,
},
debug: !isProd,
introspection: !isProd,
autoSchemaFile: {
federation: 2,
},
resolvers: { ID: BigIntIdScalarType },
plugins: [],
context: ({ req, res }) => {
return { req, res };
},
};
Issue
-
Schema Not Generated: When using
forRootAsync
, the subgraph schema does not get generated, leading to a 400: Bad Request error when the supergraph tries to introspect it. -
Gateway Errors:
- The supergraph cannot load the subgraph schema at
http://localhost:3000/graphql/
and throws an error:Error: Couldn't load service definitions for "example" at http://localhost:3000/graphql/: 400: Bad Request
- The supergraph cannot load the subgraph schema at
-
Differences:
- With the synchronous configuration, everything works as expected.
- The
orphanedTypes
parameter inbuildSchemaOptions
is required in the synchronous version but cannot be passed inforRootAsync
.
-
No Log Errors: In the failing case, there are no visible errors in the logs for the subgraph server.
Questions
- Why does the schema fail to generate when using
forRootAsync
withautoSchemaFile: { federation: 2 }
? - Does
forRootAsync
in NestJS GraphQL not fully support all Federation 2 schema generation options? - Is the
buildSchemaOptions
required fororphanedTypes
explicitly necessary in the synchronous configuration? If so, how can this be passed inforRootAsync
? - Are there differences in lifecycle hooks for schema generation when using
forRoot
vsforRootAsync
? - Is there any additional configuration or workaround required to make
forRootAsync
work with Apollo Federation 2?
Additional Information
-
Environment:
- Node.js: v18.18.2
- @nestjs/graphql: latest
- @apollo/gateway: latest
- @apollo/federation: 2.x
-
Observations:
- Switching to synchronous config fixes the issue.
- The federation supergraph does not recognize the schema for subgraphs running with
forRootAsync
.
Goal
I need to understand why the schema fails to generate in forRootAsync and how to resolve this to ensure proper Federation 2 compatibility in my subgraph.
Any insights, suggestions, or pointers to documentation would be greatly appreciated!