-
Notifications
You must be signed in to change notification settings - Fork 2.3k
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
Properly omit wrappers and google.protobuf.empty from swagger definitions #801
Properly omit wrappers and google.protobuf.empty from swagger definitions #801
Conversation
Codecov Report
@@ Coverage Diff @@
## master #801 +/- ##
==========================================
+ Coverage 49.32% 53.47% +4.15%
==========================================
Files 39 30 -9
Lines 3751 3370 -381
==========================================
- Hits 1850 1802 -48
+ Misses 1723 1389 -334
- Partials 178 179 +1 Continue to review full report at Codecov.
|
One thing i noticed:
It looks strange. I digged a bit and only the enums are prefixed with the dot (findNestedMessagesAndEnumerations(msg, reg, m, e))
I just tested, with my addition it didn't work, since it's called protobufEmpty and protobufBoolValue instead of .google.protobuf.Empty. Looks like this has once worked, but something went wrong.. Idea how to proceed? |
Sounds like at the very least we need some tests to establish the expected behaviour. If they fail, we'll have to implement some fixes. Would you be interested on adding these tests? |
Will do. These things are screwing up my swagger-ui, so i'm very interested in cleaning up where needed :) |
Okay it's quite difficult to get a test up and running. Aren't there tests where i can just provide a .proto file as input and a .json as output? That would make it much easier to get started. To be honest i spent more time to get a test working than i feel should be necessary.. I added an example with BoolValue to the examples, and this occurs in the output:
Shouldn't be there, we don't want those wrappers in the list of models. So at some point i guess .google.protobuf.BoolValue became protobufBoolValue and the switch became useless. I'm not going to commit this example because i got a lot of strange changes after re-generating with the docker image of the contributor guide.. Just added one Service, but now i have a totally unrelated diff:
I only added:
I'm a little stuck with the tooling .. or could use some help to set up a test. It's just non-trivial to get all the inputs set up, especially with multiple proto files. Is there some helper method to just load a proto file in a test, and get the descriptors etc? would really help me. |
Deleting files implies that not all generators ran. Curious findings indeed. Generally the way to test generated files like this is to compare against a "golden", known correct file. So it wouldn't be a "go test" kind of test, it'd be a shell scripting kind of test. |
Yes this is what i would have expected, but such tests are not in place it seems. They even run it from go for coverage etc : ) edit: to some extent the examples do this, because you fail the CI if there's a diff detected. |
Yes, but the examples didn't pick up the change in well known types. Maybe just adding a message using all the well known types is enough? |
ok we're getting closer, at least the examples now reproduce it. see the latest diff 2cf7065 . apparently this issue only occurs if these datatypes are used directly as method in or output. there must be some piece of code where these types are added 'differently (different names)' if they are direct method in/out. i'll have another shot after work today. edit2:
Nested uses the format with the full qualified name (e.g. .google.protobuf.Empty). So for nested values, the names are (at least internally) used like this. The other way at so choices: a) keep it as it is and add the same checks for well-known types into the switch at renderMessagesAsDefinition twice, once for the "fully qualified format" and once for the camelCase format I guess this has significant implications on the generated json, so i'll have to try it out. Maybe someone with more knowledge of the codebase can elaborate :) |
Implemented c). At least from the examples, the result looks good. In the end, all types are converted to the camel case version anyway, so it's a good idea to not do it before as well. This way, the filtering of well-known types works as expected. |
@birdayz fantastic work, really appreciate the effort you're putting in right now. Is there anything else you want to add to this PR before we review it? |
Right, I think we should just try and add a step where we generate some swagger files from the wrappers.proto as well. The generated pb.go now contains the types but I can't see a swagger file? |
I'm confused, what do you mean? |
Ok, if you want we can just resolve that in this PR and raise an issue about making sure that the generated swagger files are correctly formatted for all the well known types. I think it ought to be part of this PR to ensure that the bool and empty types are correctly formatted though. Is that already covered with existing examples? Otherwise lets just add swagger generated file of the wrappers.proto example. |
Yep it's fully covered now. So there should not be a need for a separate issue, the wrappers are now handled correctly. At least from my PoV, if these two points are valid:
The current code already does the stuff highlighted in bold, but only for in/out messages of RPC methods. Nested messages still produced those entries, even with a different name. This was fixed with 84895aa edit: the .swagger file is generated and up-to-date: https://github.com/birdayz/grpc-gateway/blob/dont_render_well-known_empty/examples/proto/examplepb/wrappers.swagger.json |
Right the thing that's still confusing me is that this PR adds a number of methods to wrappers.proto in the examples, but there are no generated swagger file changes, only pb.go changes. Is that correct? Should we not generate some swagger content for these new methods too? |
I think we have a misunderstanding here! However for the swagger part, the swagger generation code deliberately chooses to NOT generate those things - for wrappers. So this is expected and intentional that it's NOT in the .json output! See this part of the code in template.go:
This was already in place before this PR. It only affects the swagger output, not the go bindings .pb.go output. It was just buggy before my changes, for a specific subset of inputs. the generated stuff is up to date, ci does a check for that and fails in case it's not up to date. |
Not generating the types as the proto types is all well and good, but we're talking about 10ish new RPCs and no corresponding methods added to the swagger files at all. I'm wondering if it's simply because you didn't add the |
Ah now i got your concerns.. |
Great, again, thanks for your hard work here! Really appreciated. |
I added one google.api.http directive, does this look better now? |
Well slightly worryingly the string well known type is not showing up as the native string, is that not wrong? |
Also why not add all the others as well? |
i just had a look and i'm not sure if we can just omit those definitions, because clearly the path entries reference them.
so i suspect it would not even be a valid swagger. i don't know, i'll put it back to WIP for the moment until i've figured out if this ok or a better solution. |
I think ideally a google.protobuf.StringValue type would render as a string in swagger, without the message definition. I thought that was what these type exceptions were for. In any case, can we add google.api.http options for the other RPCs as well please and check those renderings too? Don't hesitate to push back, I'm happy to resolve things in separate PRs if you think its going out of scope. |
my assumption is correct, this change is not legit without fixing the underlying behavior.
So, we can't proceed this way..well, i think we could at least add a fix for the "Empty" thing, because it does really render nothing. But, in general, i agree with you: Should wrappers be used in the REST interface? clearly, clearly not. It directly shows that this is a grpc-gateway generated API and makes it look WAY less "clean". But to address this, which should certainly be possible, we would break backwards compatibility. Newly generated gateways will have a different API if they use wrappers in in/out. Maybe we can discuss this in a new issue if you want. I'm curious how you handle backwards compatibility guarantees, or how we can introduce such changes (e.g. going for a new major release). Anyway, i'll clean up this PR and try to reduce it to a minimum for the "Empty" problem, and move the rest to a new one. Thanks for all the support. |
@birdayz agreed, let's discuss the faulty behaviour separately and make a decision on what to do next. Great digging! |
58afa8b
to
f875f0b
Compare
@johanbrandhorst i've updated the PR accordingly, with changes for both Empty and Wrappers. Those two are very close (and have many common problems, like the handling of most well known types). It's squashed & rebased. I'm ready for the new code review round, if you have time. Thanks! |
f875f0b
to
e8c93a5
Compare
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.
LGTM, but let's have a look by @ivucica as well.
How can we move this forward? I make heavy use of well known types; and them being present in the definitions section of swagger is quite ugly. ;) i'd like also to improve the same situation with google.protobuf.struct; but i won't invest time into it unless i see that this comparable PR goes through :) |
I apologize for this falling between the chairs, I'll give @ivucica another few days but if I hear nothing I'll just merge it. Thanks for the bump! |
It looks like you'll need to rebase again though, could you do that please? |
- swaggerSchemaObject.Properties is now optional (pointer), because google.protobuf.Empty requires us to set Properties{} instead of nil, because this equals in Swagger to an empty JSON object (which is exactly what Empty represents and how the gateway treats it). If it's not a pointer, we can't distinguish between "not set" (in most cases, we don't want Properties to be set, instead usually just .Ref is set), and "set to an empty value e.g. Properties{} with length 0). We don't want Properties{} to occur except for specific cases, e.g. for Empty. - Wrappers and Empty are not rendered as definitions, now also for RPC Method input/output. instead, all necessary schema information is provided "in-line" via schema.type and schema.properties. - Empty is now omitted as well if it's input/output of a RPC Method.
e8c93a5
to
ed0dd91
Compare
done |
Thanks for your contribution! |
google.protobuf.Empty requires us to set Properties{} instead of nil, because
this equals in Swagger to an empty JSON object (which is exactly what Empty
represents and how the gateway treats it). If it's not a pointer, we can't
distinguish between "not set" (in most cases, we don't want Properties to be
set, instead usually just .Ref is set), and "set to an empty value e.g.
Properties{} with length 0). We don't want Properties{} to occur except for
specific cases, e.g. for Empty.
input/output. instead, all necessary schema information is provided "in-line"
via schema.type and schema.properties.