-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
add custom options to allow more control of swagger/openapi output #145
Conversation
I'm personally welcoming of the switch of the naming around swagger to open api spec. I don't have a better label/tag offhand but putting "Swagger: " into this api means a slower transition to OpenAPI Specification.
|
While OpenAPI is more accurate, Swagger is a very 'googleable' name -- it's a shame it's being dropped. Still, I've switched to the I also think using JSON here in the first place is a short-term cop-out fix (i.e. better than nothing), even though the resulting JSON looks just awful everywhere else. Long term, something that's still hierarchical such as:
would be more readable, while not much harder to parse. Perhaps even with Debian-style multilines:
That wouldn't look too horrible when seen by tooling of other languages in the generated code, either. That's a topic for some other PR, however. |
I agree that it feels off in context. When considering longer term I do think your change makes more sense. |
I wonder if we can use custom options to annotate patches. |
@yugui I like that idea -- could you propose how that might look? |
@yugui It's interesting. I guess we need to describe the Swagger schema as a .proto, in which case we might be able to do away with (what will then be) the duplicate definitions in I probably won't have a chance to work on this any time soon, though. |
@tmc, @ivucica I am worrying about parsing comments because it is not very common in protobuf convention and it has less power than custom options. |
I like this as a middle ground. @ivucica thoughts? On Thursday, May 19, 2016, Yuki Yugui Sonoda [email protected]
|
SGTM, but again, I am not sure when I'll be able to work on this. :) |
We found a Contributor License Agreement for you (the sender of this pull request) and all commit authors, but as best as we can tell these commits were authored by someone else. If that's the case, please add them to this pull request and have them confirm that they're okay with these commits being contributed to Google. If we're mistaken and you did author these commits, just reply here to confirm. |
Rebased and pushed. No other changes, i.e. still not based around proto options. |
e3b11c1
to
2bc9ddd
Compare
@yugui @tmc Could you PTAL and let me know if the direction I'm taking is worth pursuing? I can also switch to just a single option. For now I've kept the JSON in the comment, too. I have not tried to properly update all the tests, or squashing the commits, given we might change the direction. Random thought: There is an interesting side effect if there is an option to put JSON in the comment: generated code would include this metadata in its docstrings. It might not be a bad thing, either? |
@ivucica I think the custom option to supply additional openapi to inject is the way to go here. |
@tmc Yes, but which variant? I'm currently creating a larger proto descriptor instead of just accepting a piece of JSON. See PR for details :) |
@ivucica sorry I missed this comment. -1 to overloading comments, +1 to rich options.
over
Question -- can we avoid the options.swagger_swagger stutter? |
What I meant to ask is, should the proto option accept a JSON string, or as I started, describe the Swagger doc schema in the proto language :) I'll see what I can do to avoid the "stutter". :) |
Unless it presents a serious technical challenge I think the richer option is better. I think it might be worth revisiting the |
Any update on this? Looks like Swagger has officially been renamed to the OpenAPI Specification. I'm looking to open a PR to add some additional options that will allow for filtering out private/internal fields as well as marking things as Output only. Looking to this PR as guidance. |
@eddiezane This surprises me, but apparently, technically:
(Taken from the post you linked to) On multiple occasions, I was trying to figure out what to reply in relation to the rename, and my general observation is that a lot of the v2 spec still uses "Swagger" terminology (see "Swagger Object", for example). Also, proto generator that this PR applies to is called I can try to tackle this this weekend. If you see updates here by, say, mid-next week, you can take my work and run with it. (On a separate note, I think OpenAPI v3 generator should be a separate generator. A quick glance at the spec about a week ago made me think it's distinct enough that it deserves a |
Depends on PR grpc-ecosystem#134. Reverts 562956f.
…agger: '. Per discussion in grpc-ecosystem#134.
I know I'm not on your list, but I'm happy to give you a review. I think you're on the right track. I would venture to say you're probably 1 or 2 back/forths on review before we can merge this.
Do it. I think that's a better place for this.
+1, emailing them is a great idea.
You're welcome to do that but the default when we merge is to squash rebase so if you wanna ignore that then you're fine.
I would prefer if you omitted them from the openapiv2.proto file if there is no support for them.
These would be nice but the perfect shouldn't be the enemy of the good (which this clearly is very good).
Yep, that's a good idea. I think giving links to the OpenAPI definitions of these things (or copy/paste into the proto) would be good.
That's also a good idea but it can wait. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only a couple small nits and a request to get the proto extension number registered. You're SUPER close
) | ||
|
||
var swaggerExtrasRegexp = regexp.MustCompile(`(?s)^(.*[^\s])[\s]*<!-- swagger extras start(.*)swagger extras end -->[\s]*(.*)$`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
swaggerExtrasRegexp... what's that? Could you add a comment here explaining it's purpose? It doesn't seem to get used anywhere else
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's dead code from the original approach in 6ff06d8. Thanks for spotting! Removed.
@@ -175,6 +179,25 @@ func renderMessagesAsDefinition(messages messageMap, d swaggerDefinitionsObject, | |||
if err := updateSwaggerDataFromComments(&schema, msgComments); err != nil { | |||
panic(err) | |||
} | |||
opts, err := extractSchemaOptionFromMessageDescriptor(msg.DescriptorProto) | |||
if opts != nil { | |||
if err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you promote error checking to immediately after the call to extractSchemaOptionFromMessageDescription?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
} | ||
opts, ok := ext.(*swagger_options.Schema) | ||
if !ok { | ||
return nil, fmt.Errorf("extension is %T; want an Schema", ext) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: "want a Schema"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
import "google/protobuf/descriptor.proto"; | ||
|
||
extend google.protobuf.FileOptions { | ||
// TODO(ivucica): ask [email protected] to assign ID |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's do this soon so we can merge
@@ -0,0 +1,223 @@ | |||
syntax = "proto3"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice touch on reserving all the numbers for the order they appear in the swagger spec!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks :)
if spb.BasePath != "" { | ||
s.BasePath = spb.BasePath | ||
} | ||
if len(spb.Schemes) > 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the correct default here if schemes is empty? Right now I don't think it emit anything but is that the correct behavior? Should it emit "http" only so at least there is a value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question! This is correct as-is and has the same general approach that the rest of the code has: if OpenAPI v2 values are manually defined in the proto, then they overwrite the defaults; otherwise, they don't.
For schemes
value, the defaults are already defined as http
and https
, in line 639 (function applyTemplate
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! PTAL
) | ||
|
||
var swaggerExtrasRegexp = regexp.MustCompile(`(?s)^(.*[^\s])[\s]*<!-- swagger extras start(.*)swagger extras end -->[\s]*(.*)$`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's dead code from the original approach in 6ff06d8. Thanks for spotting! Removed.
@@ -175,6 +179,25 @@ func renderMessagesAsDefinition(messages messageMap, d swaggerDefinitionsObject, | |||
if err := updateSwaggerDataFromComments(&schema, msgComments); err != nil { | |||
panic(err) | |||
} | |||
opts, err := extractSchemaOptionFromMessageDescriptor(msg.DescriptorProto) | |||
if opts != nil { | |||
if err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
if spb.BasePath != "" { | ||
s.BasePath = spb.BasePath | ||
} | ||
if len(spb.Schemes) > 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question! This is correct as-is and has the same general approach that the rest of the code has: if OpenAPI v2 values are manually defined in the proto, then they overwrite the defaults; otherwise, they don't.
For schemes
value, the defaults are already defined as http
and https
, in line 639 (function applyTemplate
).
} | ||
opts, ok := ext.(*swagger_options.Schema) | ||
if !ok { | ||
return nil, fmt.Errorf("extension is %T; want an Schema", ext) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -0,0 +1,223 @@ | |||
syntax = "proto3"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks :)
LGTM. Let's get the extension numbers reserved and merge it. Thanks so much for doing this! Awesome work |
Email has been sent. Pending reply.
I'd like to leave them; they should definitely be added. Removing them (while leaving a comment and id reservation -- the right way to do it) would be extra work for not much benefit, IMHO. Also, I'll deal with the rest of the changes I mentioned soon. |
Super happy to see this progress! |
@ivucica got the email issuing us the extension IDs. When you're ready please add the new IDs and we can merge this as soon as that happens. |
New IDs have been assigned. However let's block this on move to |
…ile from echo service to a bit of everything service.
@@ -8,18 +8,18 @@ import "protoc-gen-swagger/options/openapiv2.proto"; | |||
import "google/protobuf/descriptor.proto"; | |||
|
|||
extend google.protobuf.FileOptions { | |||
// TODO(ivucica): ask [email protected] to assign ID | |||
Swagger openapiv2_swagger = 123456788; | |||
// ID assigned by [email protected] for grpc-gateway project. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a note on why they are all the same ID and why that is okay?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
@@ -8,10 +8,43 @@ import "google/protobuf/duration.proto"; | |||
import "examples/sub/message.proto"; | |||
import "examples/sub2/message.proto"; | |||
import "google/protobuf/timestamp.proto"; | |||
import "protoc-gen-swagger/options/annotations.proto"; | |||
|
|||
option (grpc_gateway.protoc_gen_swagger.options.openapiv2_swagger) = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't you need to import the relevant proto file to access options?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, that's annotations.proto, I see. I was confused by the package here, importing from protoc-gen-swagger
and then accessing a grpc_gateway
namespace. Might just be me but feels like a disconnect?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My approach for setting proto package name:
- this is the
grpc_gateway
project, and users may want some more uniqueness ->grpc_gateway
- this project contains generators
protoc-gen-grpc-gateway
andprotoc-gen-swagger
; this only applies to the latter ->protoc_gen_swagger
- these are option protos extending the proto descriptors a bit ->
options
I'm not sure why I did not go for a fully global namespace com.github.grpc_ecosystem.grpc_gateway....
. Either way there's a variety of approaches taken.
You did get me to look around so I will change this to use grpc.gateway
, as that seems to be used for the runtime and example protos.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good to me :)
I do not have swagger-codegen installed, so that was broken for me while developing.
… the approach elsewhere.
PTAL, I think this might be it for this PR on my side. I updated my Github settings so the correct email address for this PR should be used if you're squashing the PR. |
@ivucica Thanks for your works! Have you been working on |
No, I haven't. I wanted to get this merged in case someone else wants to continue, but otherwise I have not yet needed things such as oauth2 definitions in the proto. FWIW, I'll take the opportunity to speculate. I don't think I'll be working on the following, but it's an interesting thought, I think: I can imagine a solution integrating security definitions inside the grpc-gateway-compatible and swagger-annotated .proto file with an oauth2 identity provider. There may also be a complementary approach to this PR, #145 (which is just overriding Swagger fields) which is: use more definition files to describe the API, rather than just the .proto itself. That is: integrate with and read things such as:
The actual gateway would thus be complemented by an extra lib to support the above and by an oauth2 provider. That is, grpc-gateway's runtime+generator wouldn't be the only thing covered by protoc-gen-swagger, which would use this input to generate a more complete swagger description, too. |
I'm also in favor of the techniques described by @ivucica. Since grpc-gateway isn't going to be generating the entirety of your http server for you it is unlikely that we will be able to handle all cases. Oauth, to pick an example, is not going to be included in grpc-gateway, it is too complex and there are too many specific requirements for it to make a generalized form of it. Additionally, I know that people are already doing oauth based security on services by using interceptors that live outside the grpc-gateway codebase. Since it isn't a hard requirement that it be in grpc-gateway I think it should be in another repo. We have this today with @tmc's grpc-websocket-proxy. It is a simple 1 liner function call at handler registration and it makes things easy to handle. Just to demarcate the lines in the sand that I will be using to determine if functionality should be included in grpc-gateway proper.
Does anyone have any opinion on additional tests that should be included in order to prevent goalpost moving? I'm happy to codify these in the |
this is a continuation of work in grpc-ecosystem#145, which left as a TODO to check remaining options fields for the operationObject during swagger generation. This PR causes protoc-gen-swagger to check if opts.Tags exists and overwrite the default value if it does exist.
…rpc-ecosystem#145) Creates additional options that can be applied to RPCs and messages that provide additional information in the OpenAPIv2 spec. These new options allow for the inclusion of Swagger object information (maps to a .proto file): * `info` * `host` * `base_path` * `schemes` * `consumes` * `produces` * `external_docs` Service information: * `tags` * `summary` * `description` * `external_docs` * `operation_id` * `consumes` * `produces` * `schemes` Operation information (maps to a method): * `tags` * `summary` * `description` * `external_docs` * `operation_id` * `consumes` * `produces` * `schemes` Schema information (maps to a message): * `json_schema` * `descriptor` * `read_only` * `external_docs` * `example` Additionally: * Change from 'Swagger: ' to 'OpenAPI: ' prefix. It should also be relatively simple to add any field that is missing to the new OpenAPI proto objects.
Continuation of #134, pending review of that.