graphql
graphql copied to clipboard
ResolveField ignores field middleware
Is there an existing issue for this?
- [X] I have searched the existing issues
Current behavior
When resolving a field with @ResolveField
, any middleware defined on the corresponding ObjectType
's @Field
definition is ignored.
This is particularly annoying when a subset of fields for an object are resolved. Without also finding the resolver for the field that you're looking at, there is no guarantee that your middleware will execute as specified. To handle middleware-like transformations consistently, you are forced to handle all middleware-like transformations in field resolvers by hand.
Minimum reproduction code
https://stackblitz.com/edit/nestjs-typescript-starter-rkgnvv?file=src/example/example.resolver.ts&view=editor
Steps to reproduce
Use the GraphQL playground in the preview section to query for
query {
allExamples {
fieldMiddlewareField
resolveMiddlewareField
bothMiddlewareField
}
}
Expected behavior
Middleware defined in an ObjectType
's @Field
decorator should apply to the returned values from the @ResolveField
handler.
Package version
10.1.7
Graphql version
"@nestjs/apollo": "^10.1.7",
"@nestjs/graphql": "^10.1.7",
"@nestjs/platform-express": "^9.0.0",
"apollo-server-express": "^3.11.1",
"graphql": "^16.6.0",
NestJS version
9.2.1
Node.js version
16.14.2
In which operating systems have you tested?
- [ ] macOS
- [ ] Windows
- [X] Linux
Other
No response
@equal-matt
I tried to fix example.resolver.ts
, field middleware works correctly.
I don't know details, it seems that returnType in @ResolveField
needs to define type.
import { Query, ResolveField, Resolver } from '@nestjs/graphql';
import { Example } from './example.model';
@Resolver((_) => Example)
export class ExampleResolver {
@Query(() => [Example])
allExamples() {
return [{ fieldMiddlewareField: ' will be trimmed ' }];
}
@ResolveField(() => String, {
middleware: [async (_, next) => (await next()).trim()],
})
resolveMiddlewareField() {
return " won't be trimmed ";
}
@ResolveField(() => String, {
middleware: [async (_, next) => (await next()).trim()],
})
bothMiddlewareField() {
return " still won't be trimmed ";
}
}
Nice - can confirm that makes the field resolver middleware take precedence over the model middleware.
Would you like to create a PR for this issue?
If I get a moment I will, but I'd encourage anyone else to pick it up if they have the time. I'm pretty swamped right now!
Not sure if it's related, but field middleware also doesn't appear to work when defined on an @InputType
. e.g.
@InputType('SomeInput')
class SomeGqlInput {
@Field(() => String, {
description: 'The account email address.',
nullable: false,
// Field middleware in the below array doesn't seem to run
middleware: [],
})
public email!: Email;
}