ITADN

Federation referenceBy broken since v9.2.0: representation parameter undefined

#410Openericarosalina 创建于 2025-12-01
E
ericarosalinacommented
**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](https://github.com/tripss/nestjs-query/blob/master/CONTRIBUTING.md)?** Yes **To Reproduce** 1. Create a NestJS project with Apollo Federation v2 2. Configure a basic entity with `referenceBy`: ```typescript // 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 {} ``` 3. Make a federated `_entities` query 4. 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: ```typescript 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](https://github.com/nestjs/graphql/issues/945), [#2127](https://github.com/nestjs/graphql/issues/2127), [#712](https://github.com/nestjs/graphql/issues/712)). When parameter decorators are present, the `representation` parameter becomes `undefined`. **Test Coverage Gap** https://github.com/TriPSs/nestjs-query/pull/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: ```typescript // 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
2 条评论