Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gen-grpc-gateway, gen-openapiv2: add support for proto3 optional #1951

Merged

Conversation

adambabik
Copy link
Collaborator

Fixes #1278.

Even though, the main piece of code was added in google.golang.org/protobuf/compiler/protogen package, each plugin needs to explicitly enable support for proto3 optional fields. This change does exactly that. Note that gen-openapiv2 still does not fully benefit from protogen, hence, there are two helper methods enabling the feature in two different ways.

Also, this change does not treat optional fields in any different way in neither gen-grpc-gateway, nor gen-openapiv2 which actually might be required to deliver a valid experience.

@adambabik
Copy link
Collaborator Author

@johanbrandhorst I will need some help with failing bazel job. It seems that --experimental_allow_proto3_optional needs to be provided somehow in examples/internal/proto/examplepb/BUILD.bazel. This might be related.

@achew22
Copy link
Collaborator

achew22 commented Feb 5, 2021

@adambabik I think you might be blocked by bazelbuild/rules_go#2788 on adding protocopts to rules_go

Copy link
Collaborator

@johanbrandhorst johanbrandhorst left a comment

Choose a reason for hiding this comment

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

This LGTM, but I'm still slightly worried that we should do something special here. Do you think you could add an integration test that uses this new optional string? The test would go here: https://github.com/grpc-ecosystem/grpc-gateway/blob/master/examples/internal/integration/integration_test.go.

@adambabik adambabik force-pushed the add-support-for-proto3-optional branch 5 times, most recently from cca9e5d to 4700507 Compare February 11, 2021 18:04
@adambabik
Copy link
Collaborator Author

@johanbrandhorst thanks for the suggestion. Adding a case to the integration tests revealed one more missing piece, that is optional fields require different converters. I used converters from proto2 because they return pointers. It would be nice to move them to more generic place I think. It's for another PR :) I didn't add so through testing for optional fields as it is for repeated. If it's not enough, let me know.

Copy link
Collaborator

@johanbrandhorst johanbrandhorst left a comment

Choose a reason for hiding this comment

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

Thanks for the new test Adam, I think it exposes an important question - we should probably disallow optional fields in path parameters, since they're required by definition.

@@ -458,7 +460,7 @@ service ABitOfEverythingService {
// This API creates a new ABitOfEverything
rpc Create(ABitOfEverything) returns (ABitOfEverything) {
option (google.api.http) = {
post: "/v1/example/a_bit_of_everything/{float_value}/{double_value}/{int64_value}/separator/{uint64_value}/{int32_value}/{fixed64_value}/{fixed32_value}/{bool_value}/{string_value=strprefix/*}/{uint32_value}/{sfixed32_value}/{sfixed64_value}/{sint32_value}/{sint64_value}/{nonConventionalNameValue}/{enum_value}/{path_enum_value}/{nested_path_enum_value}/{enum_value_annotation}"
post: "/v1/example/a_bit_of_everything/{float_value}/{double_value}/{int64_value}/separator/{uint64_value}/{int32_value}/{fixed64_value}/{fixed32_value}/{bool_value}/{string_value=strprefix/*}/{uint32_value}/{sfixed32_value}/{sfixed64_value}/{sint32_value}/{sint64_value}/{nonConventionalNameValue}/{enum_value}/{path_enum_value}/{nested_path_enum_value}/{enum_value_annotation}/{optional_string_value}"
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is an interesting case, because if optional_string_value is truly optional, should it be possible to have it be a path parameter? Will our parser handle the case where this is unset? We may need to trigger a generation-time error when a user does this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That's a good idea! Is there a place where I could document how optional fields behave?

{
"name": "optionalStringValue",
"in": "path",
"required": true,
Copy link
Collaborator

Choose a reason for hiding this comment

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

This might break the promise of optional values

Comment on lines 369 to 372
if c.Target.GetProto3Optional() {
// Continue as a proto3 optional field does not need a special treatment.
// This condition is required as otherwise it is matched by `c.Target.OneofIndex != nil`.
} else if c.Target.OneofIndex != nil { // check if it is a oneOf field
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we invert this to avoid an else?

Suggested change
if c.Target.GetProto3Optional() {
// Continue as a proto3 optional field does not need a special treatment.
// This condition is required as otherwise it is matched by `c.Target.OneofIndex != nil`.
} else if c.Target.OneofIndex != nil { // check if it is a oneOf field
if !c.Target.GetProto3Optional() && c.Target.OneofIndex != nil { // check if it is a oneOf field

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I wanted to separate proto3 optional and oneof cases, hence, separate blocks but I can also join them. I will keep the explanation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Actually I read a bit more about it. It does use oneof under the hood.

@adambabik adambabik force-pushed the add-support-for-proto3-optional branch 2 times, most recently from 3c64f2c to a938514 Compare February 12, 2021 21:54
Copy link
Collaborator

@johanbrandhorst johanbrandhorst left a comment

Choose a reason for hiding this comment

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

LGTM

@johanbrandhorst
Copy link
Collaborator

Bazel failure seems genuine - we need to configure protoc to use the new flag:

examples/internal/proto/examplepb/a_bit_of_everything.proto: This file contains proto3 optional fields, but --experimental_allow_proto3_optional was not set.

@johanbrandhorst
Copy link
Collaborator

Please rebase on master 😄

@adambabik adambabik force-pushed the add-support-for-proto3-optional branch from a938514 to d6767e9 Compare February 18, 2021 17:42
@mvrhov
Copy link

mvrhov commented Feb 19, 2021

protoc 3.15 was released a few hours ago....

Optional fields for proto3 are enabled by default, and no longer require the --experimental_allow_proto3_optional flag.

@achew22
Copy link
Collaborator

achew22 commented Feb 20, 2021

Well... I don't think you're blocked by rules_go any more then 😉

@glerchundi
Copy link
Contributor

Whoop I didn't notice that this PR was created before creating a new one #1988 after we decided to close the attempt I made months ago #1834.

My approach in the new PR is to just make protoc-gen-grpc-gateway & protoc-gen-openapiv2 compatible with the latest protoc >3.15 releases without changing the current generators behaviour.

Feel free to do whatever you want with this new PR.

@adambabik adambabik force-pushed the add-support-for-proto3-optional branch from d6767e9 to bbd3444 Compare February 22, 2021 16:33
@adambabik adambabik merged commit 0bbdda9 into grpc-ecosystem:master Feb 24, 2021
@adambabik adambabik deleted the add-support-for-proto3-optional branch February 24, 2021 08:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support optional annotation in proto3 files in generators
5 participants