-
-
Notifications
You must be signed in to change notification settings - Fork 7.2k
Description
Bug Report Checklist
- Have you provided a full/minimal spec to reproduce the issue?
- Have you validated the input using an OpenAPI validator?
- Have you tested with the latest master to confirm the issue still exists?
- Have you searched for related issues/PRs?
- What's the actual output vs expected output?
- [Optional] Sponsorship to speed up the bug fix or feature request (example)
Description
When using a oneOf, the class generated for that property will have methods to create an instance from a dict or json. When using it, it will try to create an object for each class in the oneOf, and will give an error if either no objects could be generated or if two or more objects were generated.
My issue is that this causes a problem when inside the oneOf there are objects with no required properties, because any single dictionary will pass the validations of each oneOf object, resulting in an error since two or more objects were generated. I have additionalProperties set as True for both oneOf objects, but the current implementation of the generated classes still allows the validation to pass even if the dict object has fields that have no correspondence in that class.
openapi-generator version
7.16.0
OpenAPI declaration file content or url
components:
schemas:
foo:
oneOf:
- title: Bar1
additionalProperties: false
properties:
bar1:
type: string
type: object
- title: Bar2
additionalProperties: false
properties:
bar2:
type: string
type: object
info:
title: Title
version: 1.0.0
openapi: 3.0.4
paths: {}
Generation Details
Command:
openapi-generator-cli generate -i api.yaml -g python --additional-properties=generateSourceCodeOnly=true --package-name generated-api
Steps to reproduce
- Save the yaml above in a file called api.yaml
- Run the command above to generate the code
- Run the following python code to observe the issues (you might need to install pydantic):
from generated_api.models.bar2 import Bar2
from generated_api.models.foo import Foo
try:
Bar2.from_json('{"bar1": "bar"}')
print("BUG: Bar2 accepted unknown field!")
except Exception as e:
print(f"Expected: {e}")
try:
foo = Foo.from_json('{"bar2": "bar"}')
print(f"Success: Foo is of type {type(foo)}")
except Exception as e:
print(f"BUG: {e}")
And the output should be something like:
BUG: FooOneOf accepted unknown field!
BUG: Multiple matches found when deserializing the JSON string into Foo with oneOf schemas: Bar1, Bar2. Details:
Suggest a fix
The code for the oneOf classes to create an object from a dict is the following:
@classmethod
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
"""Create an instance of Bar2 from a dict"""
if obj is None:
return None
if not isinstance(obj, dict):
return cls.model_validate(obj)
_obj = cls.model_validate({
"bar2": obj.get("bar2")
})
return _obj
I tested changing it to
@classmethod
def from_dict(cls, obj: Optional[Dict[str, Any]]) -> Optional[Self]:
"""Create an instance of Bar2 from a dict"""
if obj is None:
return None
return cls.model_validate(obj)
As well as adding extra="forbid"
to the model_config.
The two changes together fixed my issues. The problem with the original function is that it only fetches the correct fields from each object, which would ignore the extra fields, guaranteeing the creation of a correct object, but removing its function to validate the object.
Adding extra="forbid"
here is essential, especially because I have additionalProperties
as True
in the api.yaml