-
Notifications
You must be signed in to change notification settings - Fork 58
Description
Describe the bug
The auto-generated @ResolveReference() method created by the referenceBy configuration option fails in Apollo Federation when using @nestjs/graphql v13+. The method receives undefined for the representation parameter, causing a crash when trying to access the key field.
This regression was introduced in v9.2.0 with the DataLoader implementation from PR #391 and #396.
Have you read the Contributing Guidelines?
Yes
To Reproduce
- Create a NestJS project with Apollo Federation v2
- Configure a basic entity with
referenceBy:
// user.entity.ts
import { Directive, Field, ID, ObjectType } from '@nestjs/graphql';
@ObjectType()
@Directive('@key(fields: "id")')
export class User {
@Field(() => ID)
id!: string;
@Field()
name!: string;
}
// user.module.ts
import { Module } from '@nestjs/common';
import { NestjsQueryGraphQLModule } from '@ptc-org/nestjs-query-graphql';
import { NestjsQueryTypeOrmModule } from '@ptc-org/nestjs-query-typeorm';
import { User } from './user.entity';
import { UserService } from './user.service';
const nestQueryModule = NestjsQueryGraphQLModule.forFeature({
imports: [NestjsQueryTypeOrmModule.forFeature([User])],
services: [UserService],
resolvers: [
{
DTOClass: User,
EntityClass: User,
ServiceClass: UserService,
referenceBy: { key: 'id' }, // This generates broken resolver
},
],
});
@Module({
imports: [nestQueryModule],
exports: [nestQueryModule],
})
export class UserModule {}- Make a federated
_entitiesquery - Observe crash:
Cannot read properties of undefined (reading 'id')
Expected behavior
The auto-generated @ResolveReference() method should correctly receive the representation parameter and resolve the entity.
Root Cause
In v9.2.0, the auto-generated resolveReference method was enhanced with DataLoader support, adding @Context() and @InjectDataLoaderConfig() parameter decorators:
async resolveReference(representation, @Context() context, @InjectDataLoaderConfig() dataLoaderConfig) {
const id = representation[key]; // Crashes: representation is undefined
// ...
}However, @nestjs/graphql's @ResolveReference() decorator has known incompatibilities with parameter decorators (see NestJS issues #945, #2127, #712). When parameter decorators are present, the representation parameter becomes undefined.
Test Coverage Gap
#396 added comprehensive tests for N+1 query prevention, but these tests only cover regular GraphQL queries (e.g., todoLists { items { ... } }). The tests do not exercise the Apollo Federation _entities query or the @ResolveReference() code path that the PR modified.
The PR's integration tests validate DataLoader usage in nested field resolvers (@ResolveField()), but never test the referenceBy auto-generated resolver or make any _entities queries. This is why the regression was not caught - the actual federation entity resolution was never tested.
Reproducible Test Case
Here's a minimal test that reproduces the issue:
// federated-user.spec.ts
import { INestApplication } from '@nestjs/common';
import { Test } from '@nestjs/testing';
import { getApolloServer } from '@nestjs/apollo';
import { ApolloServer } from '@apollo/server';
import { TypedDocumentNode } from '@graphql-typed-document-node/core';
import { gql } from 'graphql-tag';
import { AppModule } from './app.module'; // Your app module
describe('Federated User', () => {
let app: INestApplication;
let server: ApolloServer;
const FederatedUserQuery: TypedDocumentNode<any, any> = gql`
query FederatedUser($_representations: [_Any!]!) {
_entities(representations: $_representations) {
... on User {
id
name
}
}
}
`;
beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
imports: [AppModule],
}).compile();
app = moduleRef.createNestApplication();
await app.init();
server = getApolloServer(app);
// Create a test user in your database
// (implementation depends on your setup)
});
afterAll(async () => {
await app.close();
});
it('should resolve user via _entities query', async () => {
const response = await server.executeOperation({
query: FederatedUserQuery,
variables: {
_representations: [
{ __typename: 'User', id: 'test-user-id' }
],
},
});
// This will fail with: Cannot read properties of undefined (reading 'id')
expect(response.body.kind).toBe('single');
if (response.body.kind === 'single') {
expect(response.body.singleResult.errors).toBeUndefined();
expect(response.body.singleResult.data?._entities[0]).toMatchObject({
id: 'test-user-id',
name: expect.any(String),
});
}
});
});Desktop
@ptc-org/nestjs-query-core: 9.2.1@ptc-org/nestjs-query-graphql: 9.2.1@ptc-org/nestjs-query-typeorm: 9.2.1@nestjs/graphql: 13.2.0@nestjs/apollo: 13.2.1@apollo/subgraph: 2.12.1@nestjs/core: 11.1.9- Node: v24.5.0
Additional context
This worked correctly in v9.1.0 before the DataLoader changes. The issue affects all federated entities using referenceBy with @nestjs/graphql v13+.
This was generated by Claude Code