Skip to content

fix(graphql,apollo): ensures extensions are added to resolved fields#3779

Open
thiagomini wants to merge 1 commit intonestjs:masterfrom
thiagomini:fix/fix-extensions-in-resolved-fields
Open

fix(graphql,apollo): ensures extensions are added to resolved fields#3779
thiagomini wants to merge 1 commit intonestjs:masterfrom
thiagomini:fix/fix-extensions-in-resolved-fields

Conversation

@thiagomini
Copy link
Contributor

@thiagomini thiagomini commented Jan 2, 2026

Closes #3778

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Other... Please describe:

What is the current behavior?

Issue Number: #3778

What is the new behavior?

Extensions are correctly applied to resolved fields with renamed method names.

Does this PR introduce a breaking change?

  • Yes (I think)
  • No

Other information

⚠️ Requires Attention - Possibly a breaking change

This bug only occurs when we use a custom method name for a resolve field. If we rename the method mentioned above to status, it works as expected.

However, it's worth noting that the underlying reason for this bug is how the TypeMetadataStorage class identifies a GQL field's metadata - when we rename a resolver's method name, it handles it as a new field . The fix I'll propose for this will probably fix #3524 too - but there's a catch here - this might impact how existing applications using the code-first approach build their schemas.

Currently, if we define an Object's field's metadata in both the DTO and in the @ResolveField() decorator, the @ResolveField() will take precedence (but that's a bug, as I mentioned, because of how the metadata storage thinks the method decorated with @ResolveField is actually a new field when renamed). Let's recap the example:

@ObjectType()
export class User {
  @Field(() => ID)
  id!: string;

  @Field()
  name!: string;

  @Extensions({ isPublic: true })
  @Field(() => Status, { nullable: true, description: 'DTO Description' })
  status?: Status;
}

Notice the status field description: DTO Description.

Now, let's look at the @ResolveField definition:

@ResolveField('status', undefined, {
    nullable: true,
    description: 'Resolve Field Description',
  })
  getStatus(@Parent() user: User): Status {
    return {
      id: 'status-id',
      code: 'ACTIVE',
    };
  }

Right now, when our application schema is generated, the final description will be Resolve Field Description. But if we fix the existing bug, the field description will be updated to DTO Description.

I wanted to mention this because there might be several applications right now that will have their schema definitions changed if there are any discrepancies between the DTO and the @ResolveField, so, Kamil, you probably need to decide whether to apply this patch to a new major version or a hotfix.

await app.close();
});

it('Adds extensions to resolved field', async () => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I've asserted that this test fails without the changed I made to the type-metadata.storage

let objectOrInterfaceTypeField =
objectOrInterfaceTypeMetadata.properties.find(
(fieldDef) => fieldDef.name === item.methodName,
(fieldDef) => fieldDef.schemaName === item.schemaName,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know why this didn't compare schemaName to find existing fields' metadata. When comparing to methodName it wrongly assumes the methodName will always reflect the schemaName, which is not the case.

import { GraphQLSchemaBuilder } from '../lib/graphql-schema.builder';
import { ResolversExplorerService } from '../lib/services/resolvers-explorer.service';
import { ScalarsExplorerService } from '../lib/services/scalars-explorer.service';
import gql from 'graphql-tag';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an unused import

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

2 participants