-
Notifications
You must be signed in to change notification settings - Fork 17
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
Malfunctions around boolean parameters and defaulting #195
Comments
Yes, this is definitely a problem! One solution I was thinking of is to make these into nullable in the OpenAPI doc (pointers in Go). This way if the value is |
I don't think setting these parameters as
I believe using But the sentence in the documentation continues:
which I read as blessing to tweak the templates to use pointer types where needed, for optional properties. I think the hard part will be figuring out which parameters need this treatment, as it wouldn't be a great user experience to do this for the majority of parameters. |
Perhaps another angle is to conditionally make the field a pointer if it has a "renewable": {
"type": "boolean",
"description": "Allow token to be renewed past its initial TTL up to system/mount maximum TTL",
"default": true
}, has a {
// ...
Renewable *bool `json:"renewable,omitempty"`
// ...
} |
I've been thinking more about this. It seems to be a really hard problem, to the point where I wonder if there even is a good solution. Boolean parameters are only the tip of the iceberg. This problem can affect most/all types. Similarly, defaulting is not a clear sign of which parameters have or do not have this problem. Here are two case studies to prove this: First: Consider the API
Ironically, even though Go's slice type does differentiate between a null and an empty slice, Go's JSON library does not provide a feature to omit null slices whilst serialising empty ones. Second: Consider the API
So, what can be done? I have no suggestion that I actually like. One option would be to use pointers for every single request body parameter. But then, even if we ship a helper function like:
people's code still ends up looking like:
which is a bit on the ugly side. Another option would be to totally flip the API design, so that all parameter values need to be specified via setter functions:
but that would mean generating a huge amount more lines of code, and I suspect need some complex code to do the actual JSON serialization afterwards. Tricky... |
You are right, I did not think of the edge cases you mentioned.
Do you think this applies to all/most of the array-type request parameters? If so, we can detect them with
This seems like a very good example of something that should be flagged as "nullable" (an empty/null value has different semantic than the "zero" value).
Out of the two solutions you suggested, I think I prefer the first one. It is closer to what we used to have with the default-generated templates. Maybe a good middle-ground solution could be to define the set of conditions under which a request field should be changed into a pointer by the generation templates. For example:
Most of the request fields would not fall into these 3 categories and should provide a better UX. But for the ones that do, we can provide a |
I have a new, slightly weird, proposal but I really like it and I think it could lead to the optimal Go developer experience: What if we did one of two things, so we could insert our own semantics for omitting fields: Option 1: Fork the Option 2: Fork or rewrite just enough code to translate request model structs to In either option, the semantics we would implement would be:
and then in the openapi-generator templates, generate the Ways in which this is good For most cases, developers continue to be able to use the library in the simple way they do today. The common case remains undisrupted by needing to handle the uncommon case. All existing code continues to compile and work the same. Developers wanting to set, or not set, array or object fields have the behaviour just work. Ways in which this is bad We need to do more work to get there. A developer wanting to use the library to send a The |
I like this idea :)
My fist thought is I'm not particularly fond of having On the other hand, when a boolean field (e.g. I'll be away on a vacation for a few weeks but I'll think about this some more :) |
There are absolutely tradeoffs here. No option is obviously the best.
It's not great, I agree. However it has the potential to be less intrusive into actual use cases than everything being a pointer type even for fields which don't have any need to be. _SendZeroValue can just be ignored and not used when not needed, whereas direct assignment to pointer types frustratingly is messy.
I agree, but I think whichever option is taken, some dedicated documentation is going to be needed to explain the library's approach. If the pointer path was taken, the documentation would need explain how to set literal values, and explain why pointers have been used all over the place even when not really needed by the precise API semantics - the natural expectation would be the technique was only used where necessary.
I was thinking that _SendZeroValue would be ignored if the value was not the zero value for the type. Anyway - I acknowledge this isn't a clear cut choice. It might be worth putting a description, and some sample code, in front of as many potential users as you can find. |
Vault has a few boolean API parameters, which default to true.
Not many, but some, such as
auth/token/create
'srenewable
.At the moment the API models are autogenerated with the
omitempty
behaviour applied.Generally this is a good thing.
But in this case:
false
in request model => omitted on serialization => server defaults it totrue
true
in request model => included in serialization => server receives explicit settingtrue
There is no way to use this client library to set such things to false.
In general the same problem exists for other parameter types too, any time the Go zero value of the datatype would be meaningfully different to the API, compared with not specifying the parameter - e.g.:
This could be a bit tricky to deal with.
The text was updated successfully, but these errors were encountered: