Skip to content

Autobind Getter and Haser for Protobuf RPC#3980

Merged
StevenACoffman merged 11 commits into
99designs:masterfrom
raphaelfff:haser
Dec 31, 2025
Merged

Autobind Getter and Haser for Protobuf RPC#3980
StevenACoffman merged 11 commits into
99designs:masterfrom
raphaelfff:haser

Conversation

@raphaelfff

Copy link
Copy Markdown
Contributor

With this PR autobind now supports binding to RPC editions generated structs

I have:

  • Added tests covering the bug / feature (see testing)
  • Updated any relevant documentation (see docs)

@StevenACoffman

StevenACoffman commented Dec 29, 2025

Copy link
Copy Markdown
Collaborator

@raphaelfff Hey thanks! It looks like there are some minor lint nits and you might need to run go generate ./... and commit the results?

@coveralls

coveralls commented Dec 29, 2025

Copy link
Copy Markdown

Coverage Status

coverage: 0.0%. remained the same
when pulling 83072a6 on raphaelfff:haser
into da0c5c1 on 99designs:master.

@raphaelfff

Copy link
Copy Markdown
Contributor Author

@StevenACoffman i think its all there!

@UnAfraid UnAfraid Dec 30, 2025

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Wonder what happen here, why did the types swap?
This might not be related to your PR, but its something we may want to look into.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yup, unrelated to my changes, seems like a codegen order instability, shouldnt hold this PR tho!

@StevenACoffman StevenACoffman Dec 30, 2025

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If the codegen is unstable, it seems likely that the source of that instability is fairly recent, if it is not caused by this PR.

If it is unrelated to these changes, I would think we would have been seeing intermittent failures if it were a long-standing issue.

When I look through the commits to master: https://github.com/99designs/gqlgen/commits/master/
I do not see any failures like that (other than those that were cancelled because I impatiently merged another PR before they finished)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I honestly cannot see how this PR would interfere with type creation... but maybe you can shed some light on it :)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

BTW, @UnAfraid thanks for noticing this!

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Okay i tuned the tpl to not add a new line, this reduces the diff, it also removed that instability... not sure why/how...

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Yeah, I agree it is weird. I'm not going to pursue it until it comes back, but it might be a sign that there's something lurking we are just barely avoiding?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I vote that there is something hiding there :)

Comment thread go.mod
google.golang.org/protobuf v1.36.11
)

require golang.org/x/sync v0.19.0 // indirect

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This seems sort of odd as well.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

go mod tidy did that 🤷

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

go version go1.25.0 darwin/arm64

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🤷 then such is as the gods decree, and not for mere mortals such as I to question.

Comment thread codegen/config/config.go Outdated
Comment thread codegen/field.go Outdated
Raphael Vigee added 2 commits December 30, 2025 17:56
Comment thread codegen/field.gotpl
Comment thread codegen/field.gotpl Outdated
Comment thread plugin/federation/testdata/usefunctionsyntaxforexecutioncontext/generated/exec.go Outdated
@raphaelfff

Copy link
Copy Markdown
Contributor Author

@StevenACoffman can we get another CI run ?

@raphaelfff

Copy link
Copy Markdown
Contributor Author

@StevenACoffman comments adressed and build is green

@StevenACoffman

Copy link
Copy Markdown
Collaborator

Thanks!

@raphaelfff

Copy link
Copy Markdown
Contributor Author

How's a merge looking ?

@StevenACoffman StevenACoffman changed the title Autobind Getter and Haser Autobind Getter and Haser for Protobuf Dec 30, 2025
@StevenACoffman StevenACoffman changed the title Autobind Getter and Haser for Protobuf Autobind Getter and Haser for Protobuf RPC Dec 31, 2025
@StevenACoffman StevenACoffman merged commit af6d735 into 99designs:master Dec 31, 2025
18 checks passed
@ikonst

ikonst commented Jan 23, 2026

Copy link
Copy Markdown

I think the docs were not updated.

@StevenACoffman

Copy link
Copy Markdown
Collaborator

@ikonst Can you make a PR for this?

@ikonst

ikonst commented Jan 23, 2026

Copy link
Copy Markdown

I can try :) I was obviously trying to understand it myself by going to the docs, but I can pit Gemini against it it:
https://gemini.google.com/share/a37a1029bb6e

Does this description seem right? If so, I can make a PR based on that (obviously less verbose...).

@StevenACoffman

StevenACoffman commented Jan 23, 2026

Copy link
Copy Markdown
Collaborator

BTW, Protobuf Editions became generally available with the release of protoc 27.0.

In protobuf, the concept of a Field's "presence" is whether that field has a value. Fields are defined as having either: implicit presence, where the generated message API stores field values (only), and explicit presence, where the API also stores whether or not a field has been set.

When a Field has explicit presence, you need .HasXXX() and .GetXXX() methods on structs.

In protobuf editions, you can specify explicit default values for singular non-message fields. For example, let’s say you want to provide a default value of 10 for the SearchRequest.result_per_page field:

int32 result_per_page = 3 [default = 10];

If the sender does not specify result_per_page, the receiver will observe the following state:

  • The result_per_page field is not present. That is, the HasResultPerPage() (hazzer method) method would return false.
  • The value of ResultPerPage (returned from the "getter") is 10.

If the sender does send a value for result_per_page the default value of 10 is ignored and the sender’s actual value is returned from the “getter”.

Explicit default values cannot be specified for fields that have the field_presence feature set to IMPLICIT.

Gemini generated summary follows:


The autoBindGetterHaser flag is a configuration option added in gqlgen (specifically introduced in PR #3980) to improve compatibility with Protobuf (gRPC) generated Go structs.

Here is the explanation you can use for your documentation:

What does autoBindGetterHaser do?
When enabled, this flag instructs gqlgen to automatically look for and bind to Get() and Has() methods on your Go structs, rather than just looking for the struct fields directly.

  • Get<FieldName>(): Used to retrieve the value of the field.

  • Has<FieldName>(): Used to determine if a Nullable field is present (true) or null (false).

Rationale: Why was this added?

The primary driver for this feature is support for Protobuf (gRPC).

Protobuf Access Pattern: Modern Go code generated by protoc-gen-go (Protobuf) encapsulates fields to handle nullability and default values safely. Instead of accessing fields directly (which might be nil pointers or unexported), the standard pattern is to use the generated accessor methods:

GetEmail() returns the string value (safely handling nil).

HasEmail() returns a boolean indicating whether the field was set (important for distinguishing between an "empty string" and "null").

Removing Boilerplate: Before this flag, if you wanted to use a generated Protobuf struct as a gqlgen model, you often had to write custom resolvers for every field just to call these methods, or create wrapper structs. gqlgen's default binder would fail to find the data if the fields were unexported or if it didn't know how to check "presence" correctly.

Seamless Integration: By enabling autoBindGetterHaser, you can map your GraphQL schema directly to your Protobuf-generated Go structs. gqlgen will "do the right thing" by calling the generated Get and Has methods automatically.

Usage
You can typically enable this via the @goField directive in your schema or potentially in your gqlgen.yml configuration (depending on how globally you want it applied).

Example in Schema:

GraphQL
directive @goField(
  forceResolver: Boolean
  name: String
  omittable: Boolean
  type: String
  autoBindGetterHaser: Boolean # <--- The new flag
) on INPUT_FIELD_DEFINITION | FIELD_DEFINITION

type User {
  # Tells gqlgen to use GetEmail() and HasEmail() on the bound Go struct
  email: String @goField(autoBindGetterHaser: true)
}

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.

5 participants