Skip to content

feat(protographic): support fields with arguments and @requires directive#2653

Merged
dkorittki merged 22 commits intomainfrom
dominik/eng-8643-add-support-for-field-resolvers-with-requires
Apr 1, 2026
Merged

feat(protographic): support fields with arguments and @requires directive#2653
dkorittki merged 22 commits intomainfrom
dominik/eng-8643-add-support-for-field-resolvers-with-requires

Conversation

@dkorittki
Copy link
Copy Markdown
Contributor

@dkorittki dkorittki commented Mar 16, 2026

Adds support for protographic to generate proper protobuf messages and RPC´s for fields with arguments and the @requires directive. Instead of treating these fields as resolvables they are treated as required fields, so we generate Require* protobuf messages / RPC´s instead of Resolve*.

Checklist

  • I have discussed my proposed changes in an issue and have received approval to proceed.
  • I have followed the coding standards of the project.
  • Tests or benchmarks have been added or updated.
  • Documentation has been updated on https://github.com/wundergraph/docs-website.
  • I have read the Contributors Guide.

Summary by CodeRabbit

  • Tests
    • Added tests validating RPC/message generation for required-field scenarios that include field arguments.
  • Bug Fixes
    • Improved handling of fields with arguments and @requires/resolver directives to prevent incorrect or duplicate resolve mappings and ensure correct required-field RPC/message output.

@dkorittki dkorittki changed the title feat(protographic): add support for fields with arguments with @requires directive feat(protographic): add support for fields with arguments with @requires directive Mar 16, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 16, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Emits Args proto messages for required fields with arguments, centralizes directive lookup into a generic helper, updates field-guarding to skip @requires cases with arguments, and adds duplicated tests validating RPC/proto generation and mapping behavior for required fields with arguments.

Changes

Cohort / File(s) Summary
Federation tests
protographic/tests/sdl-to-proto/04-federation.test.ts
Added two identical tests asserting RPC and protobuf message generation for required fields with field arguments (inline proto snapshot included).
Mapping tests
protographic/tests/sdl-to-mapping/03-federation.test.ts
Added duplicated test verifying that fields with arguments + @requires do not produce a separate resolve mapping and instead appear in requiredFieldMappings.
Required fields message generation
protographic/src/required-fields-visitor.ts
Refactored request message construction to build ProtoMessage objects, conditionally emit a field_args referencing a generated {Method}Args message when arguments exist, and generate that Args message from GraphQL argument defs via graphqlArgumentToProtoField and getProtoTypeFromGraphQL.
Mapping guard logic
protographic/src/sdl-to-mapping-visitor.ts
Renamed guard variable to hasResolveDirective, preserved existing skips, and added a skip for fields that have arguments and the @requires directive so those are handled by the required-fields visitor.
Directive lookup & resolver handling
protographic/src/sdl-to-proto-visitor.ts
Replaced findResolverDirective with a generic findDirective(field, directive) helper, updated call sites, switched resolver checks to the new lookup, and added a skip for @requires-annotated fields without arguments.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main feature being added: support for fields with arguments that use the @requires directive, which is reflected across all modified files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@dkorittki dkorittki changed the title feat(protographic): add support for fields with arguments with @requires directive feat(protographic): support fields with arguments and @requires directive Mar 16, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@protographic/tests/sdl-to-proto/04-federation.test.ts`:
- Around line 1321-1402: The snapshot is stale: the generator moved
field-argument handling for required fields into a dedicated RPC
(ResolveUserPost with ResolveUserPostArgs) and RequireUserPostByIdRequest should
only include the external context; update the inline snapshot so
RequireUserPostByIdRequest no longer contains field_args, add the
ResolveUserPost RPC and its ResolveUserPostArgs message, and ensure
RequireUserPostByIdContext still contains LookupUserByIdRequestKey and
RequireUserPostByIdFields; reference the symbols RequireUserPostByIdRequest,
RequireUserPostByIdContext, RequireUserPostByIdFields, ResolveUserPost, and
ResolveUserPostArgs when making the snapshot changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 1edfb924-4a1f-44f6-8c7c-be2c25aed00f

📥 Commits

Reviewing files that changed from the base of the PR and between 02ce559 and 11d7b6d.

📒 Files selected for processing (1)
  • protographic/tests/sdl-to-proto/04-federation.test.ts

Comment thread protographic/tests/sdl-to-proto/04-federation.test.ts
@github-actions

This comment has been minimized.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
protographic/src/sdl-to-proto-visitor.ts (1)

1138-1141: Consider skipping all @requires fields in resolver RPC collection (not only arg-bearing ones).

Line 1139 currently gates on field.args.length > 0. A field with @requires and @connect__fieldResolver but no args can still generate a resolver RPC, creating a parallel resolution path.

💡 Suggested change
-        if (field.args.length > 0 && this.findDirective(field, REQUIRES_DIRECTIVE_NAME)) {
+        if (this.findDirective(field, REQUIRES_DIRECTIVE_NAME)) {
           continue
         }

Based on learnings: @requires fields are intended to be resolved by dedicated RPCs to prevent bypassing dependency requirements.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@protographic/src/sdl-to-proto-visitor.ts` around lines 1138 - 1141, The
resolver-RPC collection currently only skips fields with `@requires` if they have
arguments (the condition `field.args.length > 0 && this.findDirective(field,
REQUIRES_DIRECTIVE_NAME)`); update the logic to skip any field that has the
`@requires` directive regardless of args by using only the
`this.findDirective(field, REQUIRES_DIRECTIVE_NAME)` check (and update the
comment accordingly) so fields with `@connect__fieldResolver` but no args do not
generate a parallel resolver RPC; reference the local variable `field`, the
helper `findDirective`, and the constant `REQUIRES_DIRECTIVE_NAME` when making
the change.
protographic/tests/sdl-to-proto/04-federation.test.ts (1)

1296-1414: Add one list-argument variant to lock repeated behavior in Require...Args.

This case validates scalar args well; adding something like post(tags: [String!]!) would guard proto cardinality for generated args fields.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@protographic/tests/sdl-to-proto/04-federation.test.ts` around lines 1296 -
1414, Update the test SDL to include a list-argument variant so the generator
emits a repeated field for args: change the User.post field signature to include
a list arg (e.g., post(slug: String!, tags: [String!]!): Post!) and
re-run/generate the expected proto snapshot so RequireUserPostByIdArgs contains
a repeated string tags field (referencing RequireUserPostByIdArgs and
RequireUserPostByIdArgs.tags) and adjust
RequireUserPostByIdRequest/RequireUserPostByIdResponse expectations if needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@protographic/src/required-fields-visitor.ts`:
- Around line 339-344: The loop that maps this.requiredField.args into
requireArgsMessage.fields currently only copies typeName from
getProtoTypeFromGraphQL, causing list arguments to lose their repeated
cardinality; update the mapping inside the forEach (where
this.requiredField.args is iterated and objects are pushed onto
requireArgsMessage.fields) to capture the full result of
getProtoTypeFromGraphQL(false, d.type, true) (e.g., assign to a local variable
like protoType) and include its repeated flag (or equivalent property) in the
pushed object so list arguments are emitted with repeated: true while preserving
fieldName, typeName and fieldNumber.

---

Nitpick comments:
In `@protographic/src/sdl-to-proto-visitor.ts`:
- Around line 1138-1141: The resolver-RPC collection currently only skips fields
with `@requires` if they have arguments (the condition `field.args.length > 0 &&
this.findDirective(field, REQUIRES_DIRECTIVE_NAME)`); update the logic to skip
any field that has the `@requires` directive regardless of args by using only the
`this.findDirective(field, REQUIRES_DIRECTIVE_NAME)` check (and update the
comment accordingly) so fields with `@connect__fieldResolver` but no args do not
generate a parallel resolver RPC; reference the local variable `field`, the
helper `findDirective`, and the constant `REQUIRES_DIRECTIVE_NAME` when making
the change.

In `@protographic/tests/sdl-to-proto/04-federation.test.ts`:
- Around line 1296-1414: Update the test SDL to include a list-argument variant
so the generator emits a repeated field for args: change the User.post field
signature to include a list arg (e.g., post(slug: String!, tags: [String!]!):
Post!) and re-run/generate the expected proto snapshot so
RequireUserPostByIdArgs contains a repeated string tags field (referencing
RequireUserPostByIdArgs and RequireUserPostByIdArgs.tags) and adjust
RequireUserPostByIdRequest/RequireUserPostByIdResponse expectations if needed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7510e347-95f4-4d9d-b14d-c7b88e53f5ab

📥 Commits

Reviewing files that changed from the base of the PR and between 11d7b6d and 36b4452.

📒 Files selected for processing (4)
  • protographic/src/required-fields-visitor.ts
  • protographic/src/sdl-to-mapping-visitor.ts
  • protographic/src/sdl-to-proto-visitor.ts
  • protographic/tests/sdl-to-proto/04-federation.test.ts

Comment thread protographic/src/required-fields-visitor.ts Outdated
@github-actions

This comment has been minimized.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
protographic/tests/sdl-to-mapping/03-federation.test.ts (1)

1326-1414: Prefer focused assertions over a full snapshot for this contract.

The current snapshot is valid, but it is broader than the test intent (“no separate resolve mapping”). Narrow assertions would reduce unrelated snapshot churn.

♻️ Suggested assertion-focused rewrite
-    expect(mapping.toJson()).toMatchInlineSnapshot(`
-      { ...large snapshot... }
-    `);
+    const json = mapping.toJson();
+
+    expect(json.entityMappings).toHaveLength(1);
+    expect(json.entityMappings[0]?.requiredFieldMappings).toHaveLength(1);
+    expect(
+      json.entityMappings[0]?.requiredFieldMappings?.[0]?.fieldMapping?.original,
+    ).toBe('post');
+
+    expect(json.operationMappings.some((m) => m.original === 'post')).toBe(false);
+
+    const userType = json.typeFieldMappings.find((t) => t.type === 'User');
+    const postField = userType?.fieldMappings.find((f) => f.original === 'post');
+    expect(postField?.argumentMappings?.[0]?.original).toBe('slug');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@protographic/tests/sdl-to-mapping/03-federation.test.ts` around lines 1326 -
1414, The test currently asserts the entire mapping snapshot via
expect(mapping.toJson()).toMatchInlineSnapshot(...) which is too broad; instead
replace it with focused assertions that validate the specific contract "no
separate resolve mapping": call const json = mapping.toJson() and assert
json.entityMappings has the expected single entry (e.g.
expect(json.entityMappings).toHaveLength(1)), assert that none of
json.entityMappings has kind === 'resolve' (e.g.
expect(json.entityMappings.some(e => e.kind === 'resolve')).toBe(false)), and
then assert only the specific fields you care about in json.operationMappings
and json.typeFieldMappings using expect.objectContaining or targeted length
checks (e.g.
expect(json.operationMappings).toEqual(expect.arrayContaining([expect.objectContaining({
mapped: 'QueryUser' })])) rather than matching the entire snapshot.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@protographic/tests/sdl-to-mapping/03-federation.test.ts`:
- Around line 1326-1414: The test currently asserts the entire mapping snapshot
via expect(mapping.toJson()).toMatchInlineSnapshot(...) which is too broad;
instead replace it with focused assertions that validate the specific contract
"no separate resolve mapping": call const json = mapping.toJson() and assert
json.entityMappings has the expected single entry (e.g.
expect(json.entityMappings).toHaveLength(1)), assert that none of
json.entityMappings has kind === 'resolve' (e.g.
expect(json.entityMappings.some(e => e.kind === 'resolve')).toBe(false)), and
then assert only the specific fields you care about in json.operationMappings
and json.typeFieldMappings using expect.objectContaining or targeted length
checks (e.g.
expect(json.operationMappings).toEqual(expect.arrayContaining([expect.objectContaining({
mapped: 'QueryUser' })])) rather than matching the entire snapshot.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 11f89669-ca2e-4afc-96bc-5d3b444260c4

📥 Commits

Reviewing files that changed from the base of the PR and between 36b4452 and 4c1060d.

📒 Files selected for processing (1)
  • protographic/tests/sdl-to-mapping/03-federation.test.ts

@github-actions

This comment has been minimized.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
protographic/src/sdl-to-proto-visitor.ts (1)

1138-1140: Tighten comment wording to match the actual guard condition.

Line 1138 says all @requires fields are skipped, but Line 1139 skips only arg-bearing @requires fields. Please make the comment precise to avoid future misreads.

Suggested wording fix
-        // Skip fields with `@requires` directive, they are managed by the required fields visitor
+        // Skip arg-bearing `@requires` fields; they are managed by the required fields visitor
         if (field.args.length > 0 && this.findDirective(field, REQUIRES_DIRECTIVE_NAME)) {
           continue;
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@protographic/src/sdl-to-proto-visitor.ts` around lines 1138 - 1140, The
comment above the guard is misleading: it claims all `@requires` fields are
skipped but the code only skips fields that both have arguments and an `@requires`
directive; update the comment to precisely state that only arg-bearing `@requires`
fields are skipped because those are handled by the required fields visitor
(referencing the `field` variable, `REQUIRES_DIRECTIVE_NAME`, and
`findDirective` call so reviewers can locate the guard).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@protographic/src/sdl-to-proto-visitor.ts`:
- Around line 1138-1140: The comment above the guard is misleading: it claims
all `@requires` fields are skipped but the code only skips fields that both have
arguments and an `@requires` directive; update the comment to precisely state that
only arg-bearing `@requires` fields are skipped because those are handled by the
required fields visitor (referencing the `field` variable,
`REQUIRES_DIRECTIVE_NAME`, and `findDirective` call so reviewers can locate the
guard).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d8338ca6-8481-4276-af1f-8d855d3b09dc

📥 Commits

Reviewing files that changed from the base of the PR and between 4c1060d and 2aabf5f.

📒 Files selected for processing (2)
  • protographic/src/required-fields-visitor.ts
  • protographic/src/sdl-to-proto-visitor.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • protographic/src/required-fields-visitor.ts

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
protographic/src/required-fields-visitor.ts (1)

336-341: ⚠️ Potential issue | 🟠 Major

Preserve isRepeated when mapping required-field arguments.

On Line 338, only typeName is copied from getProtoTypeFromGraphQL(...). List-typed GraphQL arguments will be emitted as singular proto fields.

💡 Proposed fix
-      const requireArgsMessage: ProtoMessage = {
-        messageName: requireArgsMessageName,
-        fields: this.requiredField.args.map((d, i): ProtoMessageField => ({
-          fieldName: graphqlArgumentToProtoField(d.name),
-          typeName: getProtoTypeFromGraphQL(false, d.type, true).typeName,
-          fieldNumber: i + 1,
-        }))
-      };
+      const requireArgsMessage: ProtoMessage = {
+        messageName: requireArgsMessageName,
+        fields: this.requiredField.args.map((d, i): ProtoMessageField => {
+          const protoType = getProtoTypeFromGraphQL(false, d.type, true);
+          return {
+            fieldName: graphqlArgumentToProtoField(d.name),
+            typeName: protoType.typeName,
+            isRepeated: protoType.isRepeated,
+            fieldNumber: i + 1,
+          };
+        }),
+      };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@protographic/src/required-fields-visitor.ts` around lines 336 - 341, The
mapping for required-field arguments loses the repeated-ness because only
typeName is taken from getProtoTypeFromGraphQL; update the mapping in the
this.requiredField.args -> ProtoMessageField creation to call
getProtoTypeFromGraphQL(...) once (e.g., const protoType =
getProtoTypeFromGraphQL(false, d.type, true)) and include protoType.isRepeated
as the isRepeated property on the produced ProtoMessageField (alongside
fieldName, typeName and fieldNumber) so list-typed GraphQL arguments emit as
repeated proto fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@protographic/src/required-fields-visitor.ts`:
- Around line 336-341: The mapping for required-field arguments loses the
repeated-ness because only typeName is taken from getProtoTypeFromGraphQL;
update the mapping in the this.requiredField.args -> ProtoMessageField creation
to call getProtoTypeFromGraphQL(...) once (e.g., const protoType =
getProtoTypeFromGraphQL(false, d.type, true)) and include protoType.isRepeated
as the isRepeated property on the produced ProtoMessageField (alongside
fieldName, typeName and fieldNumber) so list-typed GraphQL arguments emit as
repeated proto fields.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5d143cd1-0fcf-4bf5-bcc9-051b9cc151e1

📥 Commits

Reviewing files that changed from the base of the PR and between 2aabf5f and 91b0eb8.

📒 Files selected for processing (1)
  • protographic/src/required-fields-visitor.ts

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 17, 2026

Codecov Report

❌ Patch coverage is 95.08197% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.20%. Comparing base (8529b07) to head (685f080).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
protographic/src/sdl-validation-visitor.ts 25.00% 2 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             main    #2653       +/-   ##
===========================================
+ Coverage   63.14%   86.20%   +23.05%     
===========================================
  Files         249       20      -229     
  Lines       26661     4493    -22168     
  Branches        0      997      +997     
===========================================
- Hits        16835     3873    -12962     
+ Misses       8449      599     -7850     
+ Partials     1377       21     -1356     
Files with missing lines Coverage Δ
protographic/src/required-fields-visitor.ts 88.85% <100.00%> (ø)
protographic/src/sdl-to-mapping-visitor.ts 94.61% <100.00%> (ø)
protographic/src/sdl-to-proto-visitor.ts 91.25% <100.00%> (ø)
protographic/src/sdl-validation-visitor.ts 83.16% <25.00%> (ø)

... and 265 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 17, 2026

CodeRabbit chat interactions are restricted to organization members for this repository. Ask an organization member to interact with CodeRabbit, or set chat.allow_non_org_members: true in your configuration.

Comment thread protographic/tests/sdl-to-mapping/03-federation.test.ts
@dkorittki dkorittki marked this pull request as ready for review April 1, 2026 08:37
Comment thread protographic/src/sdl-to-proto-visitor.ts Outdated
Comment thread protographic/SDL_PROTO_RULES.md Outdated
dkorittki and others added 2 commits April 1, 2026 12:35
Co-authored-by: Ludwig Bedacht <ludwig.bedacht@gmail.com>
@dkorittki dkorittki merged commit 53c88fa into main Apr 1, 2026
11 checks passed
@dkorittki dkorittki deleted the dominik/eng-8643-add-support-for-field-resolvers-with-requires branch April 1, 2026 11:14
dkorittki added a commit to wundergraph/graphql-go-tools that referenced this pull request Apr 7, 2026
…1452)

## Context

A [change in
protographic](wundergraph/cosmo#2653) allows to
treat fields with arguments to be treated as a required fields alongside
needed protobuf rpc's and message to retrieve field_arguments. A
necessary change to allow field arguments on `@requires` fields.

When giving this new proto spec and mapping to the engine such fields
were silently ignoring the arguments — the gRPC call received the
context (key + required fields) but no `field_args`, so the service
always saw zero-value arguments.

## Implementation

Wire field arguments through the `@requires` execution path (grpc
datasource, federation visitor, compiler), doing it similar to how field
resolvers already handle them.

## Tests

Three new integration + execution-plan test scenarios covering:

| Scenario | Args |
|---|---|
| Single required string arg | `prefix: String!` |
| Two args, one repeated (list) | `prefixes: [String!]!, maxResults:
Int!` |
| Nullable arg (maps to `google.protobuf.StringValue`) | `prefix:
String` |



## Checklist

- [x] I have discussed my proposed changes in an issue and have received
approval to proceed.
- [x] I have followed the coding standards of the project.
- [x] Tests or benchmarks have been added or updated.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants