Skip to content

Federation referenceBy broken since v9.2.0: representation parameter undefined #410

@ericarosalina

Description

@ericarosalina

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

  1. Create a NestJS project with Apollo Federation v2
  2. 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 {}
  1. Make a federated _entities query
  2. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions