-
-
Notifications
You must be signed in to change notification settings - Fork 6.6k
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
[Swift5]: encode nil when swift5 optional is empty #10929
[Swift5]: encode nil when swift5 optional is empty #10929
Conversation
Hey @jarrodparkes thanks for creating this PR 👍 |
Sounds good. I wanted to use an extension (like |
The problem is that this is a behaviour change. Lines 250 to 252 in e5159ef
But let's wait for feedback. |
But I'm not sure what's the right behaviour, or if there is a right behaviour.
Thanks |
@4brunu imo the behavior should be configurable. However, iirc, when this feature was implemented, it basically checked if a property can be EDIT: related commit 0f5e7d1#diff-64f663dd600a47be7f81fb31e4858eeacb9627b668c5f35b7afcc98da25916de |
I think we can create a flag like |
@aymanbagabas thanks for your feedback 👍 |
@jarrodparkes if you need help with this please let me know 🙂 |
@4brunu yes please, I would love help with this |
Here is another PR where I did something similar, add an option and use it in the mustache files, does this help? Look at the file Swift4CodeGen.java and the mustaches files for the nonpublic if else's. |
@4brunu this will give a good start I'm sure. I think the open question I'd have after a quick cursory glance is that your option is sort of a "global" option versus something I'd want to specify (1) per-model AND (2) as an array of property names |
I think it's a bit strange for an API to have different rules for different endpoints, so I think the global rule works. |
@4brunu that's fair and accurate with the API I'm working with. I'll go with that for now in my implementation. Later we could readdress the per-model/etc. if that is still a concern |
Looks good to me 👍 |
272c34c
to
c13067d
Compare
restarted work on this today 😄 ! |
@4brunu I think i've got the core of this PR ready to go now — let me know what you think 👍 |
@@ -63,7 +63,21 @@ | |||
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} func encode(to encoder: Encoder) throws { | |||
var container = encoder.container(keyedBy: CodingKeys.self) | |||
{{#allVars}} | |||
{{#encodeModelNullProperties}} | |||
{{#required}} | |||
try container.encode{{#isNullable}}IfPresent{{/isNullable}}({{{name}}}, forKey: .{{{name}}}) |
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.
@jarrodparkes if something isNullable
shouldn't we call container.encodeNil
?
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.
Maybe this should be
{{#required}}
{{^isNullable}}
try container.encode({{{name}}}, forKey: .{{{name}}})
{{/isNullable}}
{{#isNullable}}
if let {{{name}}} = {{{name}}} {
try container.encode({{{name}}}, forKey: .{{{name}}})
} else {
try container.encodeNil(forKey: .{{{name}}})
}
{{/isNullable}}
{{/required}}
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 do you think? This is more a question, than an answer, so I would like to have your feedback on this 🙂
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.
@4brunu Your code sample looks right to me, but the problems I seemed to be encountering were weird compound states with required
and isNullable
. In fact, these two booleans have confused me (and other devs on my team) quite a bit since they seem to refer to the same thing depending on context.
What I was using as my "source of truth" was regenerate the sample and make sure all optionals are wrapped with the if/let
construct OR encodeIfPresent
. If the resulting code ever tried to encode
an optional, then it wouldn't even compile.
The code I currently seemed to cover these cases well, but completely open for improvement/change. I can try your suggestion and see if the resulting code looks good.
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.
required
means if is must be present, either the value or null.
isNullable
defines if the type can be null.
https://stackoverflow.com/questions/45575493/what-does-required-in-openapi-really-mean
This makes me rethink the entire PR.
Instead of an addition, this should be a bug fix, and we don't need the new flag encodeModelNullProperties
.
I think this should be the implementation for all the cases.
{{#required}}
{{^isNullable}}
try container.encode({{{name}}}, forKey: .{{{name}}})
{{/isNullable}}
{{#isNullable}}
if let {{{name}}} = {{{name}}} {
try container.encode({{{name}}}, forKey: .{{{name}}})
} else {
try container.encodeNil(forKey: .{{{name}}})
}
{{/isNullable}}
{{/required}}
{{^required}}
try container.encode{{#isNullable}}IfPresent{{/isNullable}}({{{name}}}, forKey: .{{{name}}})
{{/required}}
What do you think?
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.
But if it's required, it should always be encoded, even if it's null.
If it's not required, it should be encoded only if it's present, or am I wrong?
So I think the current implementation is correct, or am I mistaken?
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.
I think we are both saying the same thing and the implementation is wrong.
But if it's required, it should always be encoded, even if it's null.
If it's not required, it should be encoded only if it's present, or am I wrong?
So I think the current implementation is correct, or am I mistaken?
translated
But if it is {{#required}}
, then it should always be encoded, even if it's null. ==> encode
If it's {{^required}}
, then it should be encoded only if it's present ==> encodeIfPresent
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.
We are saying the same thing 🙂
That's the current implementation on master branch
try container.encode{{^required}}IfPresent{{/required}}({{{name}}}, forKey: .{{{name}}})
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.
I think I'm going crazy :face_palm: you're right. I think I was probably just using the combination of required
and x-nullable
wrong this whole time
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.
It's normal, it's confusing the required vs nullable thing.
modules/openapi-generator/src/main/resources/swift5/modelObject.mustache
Show resolved
Hide resolved
TL;DR - I was missing |
Attempts to solve #10926.