-
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
protoc-gen-swagger: should well known types be nullable #669
Comments
@ivucica do you want to chime in here? |
@zheng1, I must admit I am confused at what's being proposed. Which well-known types would you make nullable and under what specific criteria? Closest could be protobuf's built-in Finally, I am not aware of PRs that make |
Actually this is a problem we're having over at my workplace with
This assumes that the JSON
The cases above ignores the edge case that a JSON timestamp can also possibly be
As mentioned by @zheng1, It would be great if |
I think actually this |
Unless they are proto2 |
I don't mind trying my hand at this @johanbrandhorst, but I'm afraid I'm not sure where to begin. |
I think @ivucica should be able to give some pointers. |
Not sure when I'll be getting around to studying the problem space. That is, here's some necessary things I don't know off the top of my head:
Each of these items is relatively short, I'd just need to spend the time to figure them out. Maybe just enumerating them helps you? However, note: OP says If you want to support |
Thanks for the contribution steps! |
If it's not oai3 specific then I think all of the above still apply, but the biggest problem I see is #4 on Ivan's list. It should by no means be impossible but it's no longer as simple as I first thought. Please feel free to give it a go though. |
This is still very valid. I don't really follow why this would be difficult to implement/change? ".google.protobuf.Timestamp": schemaCore{
Type: "string",
Format: "date-time",
Nullable: true,
}, Which would spit out this:
Are there other parts that need to be changed beyond the template/types? |
Thanks for your interest in the project, I'd be happy to review such a PR! |
@fgblomqvist Your example's syntax looks like Go code, and not like a It seems like in OpenAPI 2, As far as OpenAPI 3.0 and 3.1 go, I am not sure we support those in the first place (did someone contribute it?), but if we do, they're different too. Looking forward to seeing a proposal! |
@ivucica Yes that's from the I think the |
TL;DR PR #1665 added the external file support to the
It does seem the OP focused on WKT, yes -- I missed that.
I don't think individual messages (i.e. types, structs, records, ...) can ever be defined as nullable in protobuf. Message-type fields can be In Messages themselves have no 'nullability' property (the concept of whether the message itself is required or not). Fields that are typed as WKTs may or may not be However... upon closer inspection, it seems that "making individual schemas (i.e. pb messages, structs, data types) nullable" is exactly what OpenAPI 3 (and presumably OpenAPI 2) is doing. That is: in OpenAPI, the whole schema (pb message) has to be nullable or not. As a side note, this is confusing to me: why would you define a whole schema as nullable or not? Would it not be prudent to have a single schema defined in one place, separating the concern whether or not it's nullable in various contexts? OpenAPI seems to have chosen to define two schemas, one for nullable or another. Unless I'm misreading something. Having said this, yes, I assume we
Yep, while investigating this, I realized that it seems like this is already supported. Please refer to protoc-gen-openapiv2/options/openapiv2.proto#L192 -- note the Note how there are many extensions defined in examples/internal/proto/examplepb/unannotated_echo_service.swagger.yaml and which get output into https://github.com/grpc-ecosystem/grpc-gateway/blob/ae3f3cc0db241c509ebc7b358039cb9f6af18fca/examples/internal/proto/examplepb/unannotated_echo_service.swagger.json. Can you please check if this allows you to set |
Me and @ivucica discussed this a bit offline and I think it comes down to the question of whether Maybe the next step would be to test running one of the swagger generators with a manually enhanced generated swagger.json with some x-nullable sprinkled into the parameter objects where desired. How does that sound @fgblomqvist? I don't think this will be as easy as just always setting |
Alright, so I did misunderstand, indeed.
Re-reading the stackoverflow answer for reference of syntax, it looks like this is meant to be properties. However, we are inlining only primitive properties; any message type is going to be Presumably, we can blindly generate If we do choose to generate both of the schemas for each of the messages and enums, i.e. anything output to the
would be fine? And for the primitive types, we set The immediate workarounds specifically for WKTs, for everyone that needs only nullable WKTs, is to try using |
Thank you both for taking the time to think about this issue! It does indeed seem like using that override file could potentially work, though, I have yet to investigate/try it myself. And yes, you're right in that it's perhaps not as easy as it sounds to solve this, due to the "required"-stuff in proto2. I don't think the default should be In proto3, WKTs should be outputted as nullable at all times. That's simple enough. However, I don't know what the rules would look like in proto2 since I haven't worked much with that. |
You are right, in the sense that value of null != absence of value != default value. However, some of it may be equal depending on whether you're talking about proto2 or proto3. Broadly speaking:
But that's the use of Only language guide for proto3 specifies the JSON mapping. It does not say it should be emitted except in case of WKT
I assume you meant language guides for proto2 and proto3, because the proto specs for proto2 and proto3 are really just defining the language grammar for
Why just WKT? Every message is equally nullable/non-nullable in proto3, and WKTs are not special. I'd say if someone is going to do this, it should be done right for all messages and fields and nost just WKTs. It should be done for both proto2 and proto3:
You are right that some WKTs are a bit special: fieldmasks, timestamps, durations, lists and such are defined to be output as primitive types. But they then become regular primitive types. So, the same principle of 'announcing nullability' should be used for all fields. [You may note that I strangely kept wondering why WKTs are brought up as special. That's because I didn't remember that timestamps and such have special encodings.] So either we use the
How does this sound? |
I think that sounds good. Thanks again for taking the time to write such thorough responses. |
I've added support for |
Sorry, long post. I implemented the field behavior approach on your changes, @ewhauser (thx!). Diff attached below for reference. But... First, the definition of OPTIONAL in the field behavior spec is pretty clear that it's Optional in the proto v2 sense. And it has the attendant restrictions, including that the first (or only) field in a protobuf Message cannot be OPTIONAL. While this "works", I'd have to change the order of one of my existing messages, and someone else down the road will have to remember that OPTIONAL will be silently ignored on the first field. Combine this with the fact that Nullable isn't really exactly the same as Optional, and I'm stuck with stinkface. The motivation for me is that google.protobuf.Timestamp over swagger will always be populated with the delightful @ivucica I'm not convinced that, given the orthogonal semantics and restrictions of Proto's Optional, that Optional == Nullable is the best approach. Also, the extensions approach doesn't seem feasible. First, I don't see extensions as a valid field at the Personally, I feel like choosing I would think a string with a format would still qualify as a scalar, so nullable non-scalars doesn't really scratch the itch. I'm also suspicious of the concept of making WKTs nullable by default, since this feels like it conflicts with the protobuf mechanism and would of course break backwards-compatibility. It's also a harsh optional switch to throw, which would change generation for all WKTs. Abandoning google.protobuf.Timestamp and using a "plain" string with a presumed RFC3339 format is safe, and I would probably already do that if I didn't want to retain the serialization benefits of g.p.T for GRPC clients. The only somewhat narrow option I can think of is to have Until then, there's always
|
FWIW - Google is using |
Yeah, though to be fair they're annotating all of the fields as if they were proto v2, so I'm not sure it's intended to specifically address nullability of g.p.Timestamp? |
Just to make sure I didn't miss any solution in this thread: at the moment there is no way to distinguish between |
@powerman Alas, not that I can see off-hand, and I'm assuming there's no google.protobuf markup for this situation. Even for a bare WKT Int32, you'd need the above patch. Applying OPTIONAL to a Map would/should only apply to the map itself, not its values/additional_properties. And I wasn't able to figure out a workable yaml solution. Conceivably, one could mark proto maps with some kind of
I'm just thinking out loud there—I'm not sure if FWIW, after having tried to use maps many times, I now try to avoid them in proto specs, opting for repeated Messages over the wire instead—even though it implies an additional conversion. The GRPC-GW concept is very powerful IMO, but there are rough edges that exist between OpenAPI and GRPC that require occasional compromise, IME. |
Nope, this change in swagger.json doesn't affect grpc-gateway and it doesn't allow null values. |
Not what you want, I'm sure, but this is the only thing I can think of:
Then use the script. I'm pretty sure this solution is worse than the problem, though. |
nullable
[link] field to define schema can benull
value.go-swagger
support vendor extensions forx-nullable
[link]Should
protoc-gen-swagger
convert well know types to nullable type?The text was updated successfully, but these errors were encountered: