Prototype: FieldDirective - auto-wrap resolvers with directive functions#229
Open
captbaritone wants to merge 5 commits intomainfrom
Open
Prototype: FieldDirective - auto-wrap resolvers with directive functions#229captbaritone wants to merge 5 commits intomainfrom
captbaritone wants to merge 5 commits intomainfrom
Conversation
When a `@gqlDirective` function's return type is `FieldDirective` (exported
from grats), Grats automatically composes the directive wrapper around the
field resolver in the generated schema. This eliminates the need for manual
`mapSchema` + `getDirective` wiring for the common case of field-level
directive behavior (auth, rate limiting, logging, etc).
The directive function is called with its annotation arguments and returns
a higher-order function that wraps the resolver:
resolve: rateLimit({ max: 10 })(function resolve(source) { ... })
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
👷 Deploy Preview for grats processing.
|
❌ Deploy Preview for grats failed. Why did it fail? →
|
- Move FieldDirective detection from syntactic name check in Extractor to a type-aware transform (resolveFieldDirectives) that uses the TS checker to verify the return type resolves to grats' FieldDirective type - Update production-app example to use FieldDirective (removes mapSchema) - Update directive definitions docs with FieldDirective section - Update directive annotations docs to recommend FieldDirective approach - Update permissions guide to use FieldDirective pattern - Add integration test that verifies directives execute at runtime (both logging and result transformation) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove unused eslint-disable in Types.ts - Format resolveFieldDirectives.ts with prettier - Fix integration test: use args with typed result instead of `never` args (which caused empty call) and `unknown` concatenation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace `type Query = unknown` + `@gqlField` with `@gqlQueryField` in both unit and integration test fixtures - Add explicit `next: GraphQLFieldResolver<...>` type annotations in all FieldDirective examples: docs snippets, permissions guide, production-app, and test fixtures Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Use ctx.resolveNodeDeclaration() (new public method on TypeContext) instead of directly calling checker.getSymbolAtLocation and checker.getAliasedSymbol. This keeps the checker encapsulated within TypeContext. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
FieldDirectivetype exported fromgratsthat directive functions can return to opt into automatic resolver wrapping@gqlDirectivefunction returnsFieldDirective, Grats composes the directive wrapper around the field resolver in the generated schemamapSchema+getDirectivewiring for the common case of field-level directive behaviorExample
Generated output
Design decisions
FieldDirectiveget this behavior. Existing directives withvoidreturn type continue to work as metadata-only.FieldDirectiveis detected by name in the return type annotation (the extractor is purely syntactic, no type checker).FieldDirectivedirectives on a single field nest naturally (outermost directive listed first).@semanticNonNullalready wraps resolvers at codegen time.Related
Test plan
fieldDirectiveWrapper.tsvalidates the generated output🤖 Generated with Claude Code