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

[protoc-gen-openapi] Support Fully Qualified Schema Names and Annotations for File/Document and Method/Operation #324

Merged
merged 3 commits into from Mar 30, 2022

Conversation

jeffsawatzky
Copy link
Contributor

@jeffsawatzky jeffsawatzky commented Mar 28, 2022

This does a couple things:

  1. Refactor the code a little to provide the actual message and field instances to more places instead of just the descriptor
  2. Removed the formatMessageRef function as it was basically a duplicate of formatMessageName, and with the above refactor it wasn't needed anymore
  3. Added support for adding the message package name to the schema name to support fully qualified schema names. This is done with the new option fq_schema_naming
  4. Added support for options on the File (which are used on the OpenAPI Document) and Method (for the OpenAPI Operation)
  5. Added some tests for the new features
  6. Added functionality to easily generate new test fixtures and update existing test fixtures if needed.

Fixes #308
Fixes #309
Fixes #322

@jeffsawatzky jeffsawatzky requested a review from a team as a code owner March 28, 2022 15:57
@google-cla
Copy link

google-cla bot commented Mar 28, 2022

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

For more information, open the CLA check for this pull request.

@jeffsawatzky
Copy link
Contributor Author

@googlebot I signed it!

@jeffsawatzky jeffsawatzky changed the title Support Fully Qualified Schema Names [protoc-gen-openapi] Support Fully Qualified Schema Names Mar 28, 2022
@jeffsawatzky jeffsawatzky changed the title [protoc-gen-openapi] Support Fully Qualified Schema Names [protoc-gen-openapi] Support Fully Qualified Schema Names and Option Annotations for File/Document and Method/Operation Mar 28, 2022
@jeffsawatzky
Copy link
Contributor Author

@timburks Could you have a look at the PR when you have time. Thanks!

@jeffsawatzky jeffsawatzky changed the title [protoc-gen-openapi] Support Fully Qualified Schema Names and Option Annotations for File/Document and Method/Operation [protoc-gen-openapi] Support Fully Qualified Schema Names and Annotations for File/Document and Method/Operation Mar 28, 2022
@jeffsawatzky jeffsawatzky mentioned this pull request Mar 29, 2022
@jeffsawatzky
Copy link
Contributor Author

@timburks I'm in the process of bringing the functionality of protoc-gen-openapi close to the grpc-gateway-openapiv2 one in terms of customization, but all may changes are based on each other.

Do you want everything in one huge PR? Or would you prefer smaller ones? If smaller ones, then this PR is what most of the newer ones will be based off of so I would really appreciate it if the could get reviewed, and if you approve, merged.

Thanks!

@timburks
Copy link
Contributor

@jeffsawatzky Thanks for this work and your explanations. I'll review (and expect to approve) this today; from your note at the top, it all SGTM.

Would you mind spelling out what you mean by "bringing the functionality of protoc-gen-openapi close to the grpc-gateway-openapiv2 one in terms of customization"? What specific things are you hoping to add? Just wanting to sync on top-level goals.

Thanks!

/cc @morphar

@jeffsawatzky
Copy link
Contributor Author

jeffsawatzky commented Mar 29, 2022

@timburks being able to embed OpenAPI elements into the proto as options so you can define extra things like security on a method within the proto file. I've added examples of this to the tests in this PR.

Also, envoy and grpc-gateway return errors using the google.rpc.Status message type and currently this plugin doesn't support the google.protobuf.Any message properly which is used by google.rpc.Status message (see #327 which adds support for this)

Copy link
Contributor

@timburks timburks left a comment

Choose a reason for hiding this comment

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

@jeffsawatzky thanks, this looks great. I really like the options annotations and how well they fit into the gnostic data structures.

I'll let this sit overnight (California time) in case @morphar has time to look and comment and if no objections come up, I think we can merge this tomorrow morning (PDT).

option go_package = "./openapiv3;openapi_v3";

extend google.protobuf.FileOptions {
Document document = 1042;
Copy link
Contributor

Choose a reason for hiding this comment

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

So (just digesting), this allows an arbitrary OpenAPI document to be attached to a file, presumably a partial document that gets overlaid/merged onto the generated OpenAPI spec.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@timburks Correct. It will do a proto merge on the result Document and any openapi.v3.document options it finds while compiling the proto files.

}

extend google.protobuf.MethodOptions {
Operation operation = 1042;
Copy link
Contributor

Choose a reason for hiding this comment

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

Similarly, this merges an Operation into the operation generated for a method. This is a gnostic type (as is Document) - and I notice from your example that you're assigning them with valid structs, which are unintuitive to most OpenAPI users but fit the gnostic protobuf model - and I think that consistency is good. Without looking through your generator code (yet), I guess that makes it easier to merge these with the generated doc since that's working on gnostic protobuf-based structs.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Protocol Buffer options need to be defined using protocol buffers themselves. So you will never get a 1-1 mapping of the options structure with OpenAPI structure as protocol buffers are strictly typed and yaml/json are not. Also, this is similar to how the protoc-gen-openapiv2 generator works from the grpc-gateway project (though they use protocol buffers that are specific to OpenAPI v2/Swagger). I think most developers that will use this will understand this.

Since I need to use protocol buffer messages for the options, I reused the same ones that gnostic was already using to make merging them easier, as you said.

// Merge any `Document` annotations with the current
extDocument := proto.GetExtension(file.Desc.Options(), v3.E_Document)
if extDocument != nil {
proto.Merge(d, extDocument.(*v3.Document))
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice, this seems really clever and elegant. I wonder if there are any other places (besides methods and files) where it would make sense to attach a partial document - maybe messages or fields?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I can add the same for Messages=>Schemas and Fields=>Parameters. But didn't want to do too much in case you reject the whole idea. I can do this in a separate PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think that would be great, thanks!

Title: flags.String("title", "", "name of the API"),
Description: flags.String("description", "", "description of the API"),
Naming: flags.String("naming", "json", `naming convention. Use "proto" for passing names directly from the proto files`),
FQSchemaNaming: flags.Bool("fq_schema_naming", false, `schema naming convention. If "true" prefixes the schema name with the proto message package name`),
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's spell out what "fq" stands for here in the help string, maybe like this:

If "true", generates fully-qualified schema names by prefixing them with the proto message package name.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have a couple more PRs coming. I will update the help string there, if that's ok with you.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, SGTM

// The Go package name.
option go_package = "./openapiv3;openapi_v3";

extend google.protobuf.FileOptions {
Copy link
Contributor

Choose a reason for hiding this comment

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

The other files in this directory are automatically-generated - that's not a problem, and I think this is a good place to put this file, especially since it refers to types defined inside the package.

Eventually (not necessarily in this PR) I think it would be good to have some documentation here of how these annotations work. google/api/http.proto is a good example of this - though I'm not thinking of anything nearly as elaborate as that, that file seems to be a good example of where to put proto documentation -- in comments in the protos so that it never gets separated.

@morphar
Copy link
Collaborator

morphar commented Mar 30, 2022

Sorry, I was away from my computer, I'll have a look at it now :)

@morphar
Copy link
Collaborator

morphar commented Mar 30, 2022

I have no comments to add whatsoever! It looks really good to me 👍

As far as I can tell, all existing things just works, while adding some nice functionality.
I just did a full run of tests on a local project (gRPC, gRPC-Web, Envoy, OpenAPI, etc.) and nothing breaks there either.

Really nice @jeffsawatzky 👍

@ppaanngggg
Copy link
Contributor

so, merge this plz. I really need this feature too. 👍

@jeffsawatzky
Copy link
Contributor Author

@timburks / @morphar once you merge this PR, can you also take a look at my other PR #327 which is based on this? I have some more functionality that I would like to add for my use case, such as adding an option for a default response for error responses that use the google.rpc.Status message (since Envoy and grpc-gateway both use google.rpc.Status as their error response). But it would be helpful if these two PRs could be merged first.

@timburks timburks merged commit ec4d35c into google:master Mar 30, 2022
@ppaanngggg
Copy link
Contributor

Could you please add a Tag on this commit? @timburks @morphar

@morphar
Copy link
Collaborator

morphar commented Mar 31, 2022

It's only @timburks who can add tags and versions. I'm just a contributor :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants