swagger-api / swagger-api/swagger-codegen
[python-flask] model instantiation through dict does not respect required default properties
Nobody has claimed this yet.
- Dominant language
- Mustache
- Stars
- 17.8k
- Forks
- 6k
- PR merge metrics
- No merged PRs in 30d
Description
Description
each generated "model" has the method from_dict which is used in the controller in order to deserialize the JSON into an actual instance of the dto. when calling the endpoint this request will fail, because the default parameters are not respected in the call-chain.
curl -d 'some_json_does_not_matter' http://localhost:3000/your/endpoint
ERROR in app: Exception on /api/rest/v1/train [POST]
Traceback (most recent call last):
# bla bla, I've stripped some here
File "/y/controllers/my_controller.py", line 23, in initialize_model_version
model_metadata = MyDto.from_dict(connexion.request.get_json()) # noqa: E501
File "/y/models/mydto_metadata.py", line 45, in from_dict
return util.deserialize_model(dikt, cls)
File "/y/util.py", line 108, in deserialize_model
instance = klass()
File "/y/models/mydto_metadata.py", line 32, in __init__
self.sentences = sentences
File "/y/models/mydto_metadata.py", line 66, in sentences
raise ValueError("Invalid value for `anything`, must not be `None`") # noqa: E501
ValueError: Invalid value for `anything`, must not be `None`
127.0.0.1 - - "POST /your/endpoint HTTP/1.1" 500 -
I've briefly scrolled through the open issues, but found non containing this error. some more details with links containing the template references below.
controller, we receive the request here:
def foo(my_dto=None): # noqa: E501
if connexion.request.is_json:
my_dto= MyDto.from_dict(connexion.request.get_json()) # noqa: E501
dto, the constructor with parameters is problematic:
class MyDto(Model):
def __init__(self, sentences=None): # noqa: E501
# some init stuff here
self.anything= anything # this line fails, because the setter checks the required property
@classmethod
def from_dict(cls, dikt) -> 'MyDto':
return util.deserialize_model(dikt, cls)
@anything.setter
def anything(self, anything):
if anything is None:
raise ValueError("Invalid value for `anything`, must not be `None`") # noqa: E501
and the utility class (util.py):
def deserialize_model(data, klass):
instance = klass() # <-- this is where the server throws an error
if not instance.openapi_types:
return data
for attr, attr_type in six.iteritems(instance.openapi_types):
# sets the attributes here, not in the constructor
Swagger-codegen version
through the gradle plugin org.openapi.generator, version 6.1.0:
openApiGenerate {
generatorName = "python-flask"
inputSpec = "${project.rootDir}/specs/api.yml".toString()
outputDir = "${project.buildDir}/generated-resources".toString()
}
Swagger declaration file content or url
doesn't really matter, but it's important that the property is required!
components:
schemas:
MyDto:
type: object
required:
- anything
properties:
anything:
type: string
Command line used for generation
as said, through the gradle plugin.
Steps to reproduce
I think you could generate a server using the petstore API, but haven't tried it.
Related issues/PRs
didn't find any.
Suggest a fix/enhancement
now the problem is you cannot just alter the constructor, because when initializing the class using the constructor you probably want that check to happen. you just don't want it to happen when calling from_dict. I think, the only way around this is using an empty constructor and a "builder-method" (another @classmethod) as replacement for an "all-args-constructor". but, this change would be breaking.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with modules/swagger-codegen/src/main/resources/flaskConnexion/model.mustache and util.mustache, then inspect controller.mustache to follow the generated from_dict path. Reproduce the required-property case with a python-flask server generated from the supplied schema; done means deserialization no longer fails during empty model initialization while direct constructor validation remains intact.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- openapi, python
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100