Repository navigation
New behavior around optional nested objects breaks deserialization when explicit null is returned #343
Description
Activity
Thanks for filing the bug report! I'll try to get a fix in for this by the end of the week 😊
It's certainly possible, that PR does a lot to clean up that code. If you get a chance to check out that branch and confirm, that would be great! I plan on also re-reviewing that PR later this week, but there's been a lot of back and forth on it so far so I don't know how long until it's ready to merge.
Hey @joshzana now that #332 is done, I took a deeper look at this. Turns out this is actually working as intended. In 0.8.0 we tightened up our
requiredandnullablehandling, so the previous behavior which happened to be working for you in 0.7.3 was actually incorrect.In OpenAPI, there is a difference between something being not-required and something being nullable. If something is not required (as is the case with your example), it's possible that it will not be included at all. If something is nullable, it's possible for it to have an explicit
nullvalue. In this case, the schema looks like this:{ "title": "ResourceWithOptional", "type": "object", "properties": { "item": { "$ref": "#/components/schemas/ItemResource" } } }Where that
itemproperty is notrequired(if it were, there would be a"required": ["item"]in the schema) meaning it can be omitted. However,itemis also notnullable(if it were there would be a"nullable": truein the declaration ofitem) meaning explicitnullis not allowed and therefore not expected.I've run into this issue quite a bit using FastAPI in the back end and TypeScript in the front end. If something is
not requiredit can beundefinedwhereas if something is nullable it can benull. With Pydantic, declaring a field asOptional[T]means it's not required (can be omitted), but does not setnullable. If you want to pass an explicitnullyou need to declare your field like this:from pydantic import Field class ResourceWithOptional(BaseModel): item: Optional[ItemResource] = Field(None, nullable=True)
If you are never going to omit the field, but rather always pass explicit
null, then you can also include arequired=Trueparam in there to get rid of theUnset(in our generated clients) orundefined(in TS) option.That was a long-winded explanation, but I know this particular facet of OpenAPI can be very confusing, especially when working from Python where there is only 1 type of
null. I'm going to close this issue, but let me know if you have any questions, I'm more than happy to help!Reacted by Josh Zana
Describe the bug
We use FastAPI as an API server and generate a python client with
open-api-clientthat is then used to run integration tests. Our team is using 0.7.3 but I was trying to update to 0.8.0. When doing so, we ran into the following exception running our test suite:I was able to narrow down the problem to handling of
Optional[T]objects within response models. Here is a minimal repro:To Reproduce
Steps to reproduce the behavior:
resource_with_optional.pyin thefrom_dictmethod:Expected behavior
I expect that this allows for an explicit
nullto be returned, as was the case in openapi-python-client==0.7.3, where the generated code looks like this:OpenAPI Spec File
Desktop (please complete the following information):
Additional context
FastAPI has support for excluding nulls from responses with
response_model_exclude_nonebut this means changing how our API works to suit the sdk generator, which I would prefer not to have to do.The new behavior I was referring to seems to have come in with #334