Openapi-generator: [BUG][Python-Flask] Missing required argument on PUT, POST, PATCH

Created on 12 Dec 2018  路  3Comments  路  Source: OpenAPITools/openapi-generator

Description

PUT /data fails to provide positional argument when Data is an object type.

Calling function: <function data_put at 0x7fd26bd3b1e0> with args: {}
[2018-12-12 09:58:56,228] ERROR in app: Exception on /data [PUT]
Traceback (most recent call last):
  File "/home/tom/.local/lib/python3.5/site-packages/flask/app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/tom/.local/lib/python3.5/site-packages/flask/app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/tom/.local/lib/python3.5/site-packages/flask/app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/tom/.local/lib/python3.5/site-packages/flask/_compat.py", line 35, in reraise
    raise value
  File "/home/tom/.local/lib/python3.5/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/tom/.local/lib/python3.5/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/tom/.local/lib/python3.5/site-packages/connexion/decorators/decorator.py", line 73, in wrapper
    response = function(request)
  File "/home/tom/.local/lib/python3.5/site-packages/connexion/decorators/uri_parsing.py", line 132, in wrapper
    response = function(request)
  File "/home/tom/.local/lib/python3.5/site-packages/connexion/decorators/validation.py", line 165, in wrapper
    response = function(request)
  File "/home/tom/.local/lib/python3.5/site-packages/connexion/decorators/decorator.py", line 44, in wrapper
    response = function(request)
  File "/home/tom/.local/lib/python3.5/site-packages/connexion/decorators/parameter.py", line 131, in wrapper
    return function(**kwargs)
TypeError: data_put() missing 1 required positional argument: 'data'
127.0.0.1 - - [12/Dec/2018 09:58:56] "PUT /data HTTP/1.1" 500 -

I've seen this also fails with POST and PATCH.

Please note that this does work fine when the Data is not an object type. For example when using:

components:
  schemas:
    Data:
      type: string
openapi-generator version

I used OpenAPI generator CLI version 4.0.0-SNAPSHOT:
https://oss.sonatype.org/content/repositories/snapshots/org/openapitools/openapi-generator-cli/4.0.0-SNAPSHOT/openapi-generator-cli-4.0.0-20181210.103357-85.jar

OpenAPI declaration file content or url

See python-flask-required-body.yaml in the attached zip-file:
python-flask-required-body.zip

Command line used for generation
java -jar openapi-generator-cli-4.x.jar generate -i ./python-flask-required-body.yaml -g python-flask -o ./python-flask-required-body/
Steps to reproduce
  1. Generate the server code

    ./python-flask-required-body.sh

  2. Start the server

    (cd python-flask-required-body && python3 -m openapi_server)

  3. Perform a client request

    curl -X PUT "http://localhost:8080/data" -H "accept: /" -H "Content-Type: application/json" -d "{\"myItem\":\"myItem\"}"

    Returns:

    {
     "detail": "The server encountered an internal error and was unable to complete your request.  Either the server is overloaded or there is an error in the application.",
     "status": 500,
     "title": "Internal Server Error",
     "type": "about:blank"
    }
    
Related issues/PRs

Related issues/PRs for openapi-generator:

  • #1758

I found a similar issue in connexion:

Suggest a fix

Either:

  1. Workaround as used in #1758 (commit https://github.com/OpenAPITools/openapi-generator/pull/1758/commits/39e4441a6e7498f432321adef2930f0298ea5526#diff-23008aab5bc1adc4749f4fa8e9ebb94c):

Set the x-codegen-request-body-name: body in the requestBody's schema.

  1. You need to provide the x-body-name in the requestBody's schema so it matches the (positional) function argument name.

See also Automatic Parameter Handling at connexion:

In the OpenAPI 3.x.x spec, the requestBody does not have a name. By default it will be passed in as 'body'. You can optionally provide the x-body-name parameter in your requestBody schema to override the name of the parameter that will be passed to your handler function.

  1. Keep name body for the (_single_?) (_positional_) argument.
Bug

Most helpful comment

If you look at the source code for connexion, it tries to send the requestBody content to the operation as a named argument. The argument's name is defaulted to "body" in the absence of "x-body-name" in the openapi.yaml. Unfortunately, the openapi-generator's Python/Flask/Connexion Java simply doesn't add the extension for requestBody parameters.

I've discovered the third workaround below works if you want to be able to re-generate your code without manually editing either the openapi.yaml file or your controller modules.

  1. Copy the controller.mustache template to your templates dir and edit it.

  2. Leave the parameter as is if isBodyParam is false, otherwise rename it to body:

def {{operationId}}({{#allParams}}{{^isBodyParam}}{{paramName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}{{^required}}=None{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}):

  1. Then way down after the docstring ends, add in these middle three lines to assign the value of body to the desired parameter name:
    {{#allParams}}
{{#isBodyParam}}
    {{paramName}} = body
{{/isBodyParam}}
    {{^isContainer}}
  1. If you're not already using templates, run the code gen with the -t templates/dir flag. In recent openapi-generator versions, this should pick up just the mustache templates you've provided.

All 3 comments

On the suggested fixes in the petstore example.

  1. Updated the default_controller.py
def add_pet(body):  # noqa: E501

which worked fine.

  1. If I add the x-body-name to the requestBody/schema
    post:
      description: Creates a new pet in the store.  Duplicates are allowed
      operationId: addPet
      requestBody:
        description: Pet to add to the store
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/NewPet'
              x-body-name: new_pet

or the components/schemas/NewPet

    NewPet:
      required:
        - name
      properties:
        name:
          type: string
        tag:
          type: string
      x-body-name: new_pet

the x-body-name isn't copied through to the generated spec in openapi_server/openapi/openaip.yaml. If I manually add it to this file here

            schema:
              x-body-name: new_pet
              $ref: '#/components/schemas/NewPet'

everything works fine.

Thanks for the information above. It helped me get past a sticky spot on my project.

I just ran into the same problem.
Instead of changing the output .yaml file, wou can simply change the new_pet argument in the generated python method to body.
If you do so, you do not need to add x-body-name anywhere.

If you look at the source code for connexion, it tries to send the requestBody content to the operation as a named argument. The argument's name is defaulted to "body" in the absence of "x-body-name" in the openapi.yaml. Unfortunately, the openapi-generator's Python/Flask/Connexion Java simply doesn't add the extension for requestBody parameters.

I've discovered the third workaround below works if you want to be able to re-generate your code without manually editing either the openapi.yaml file or your controller modules.

  1. Copy the controller.mustache template to your templates dir and edit it.

  2. Leave the parameter as is if isBodyParam is false, otherwise rename it to body:

def {{operationId}}({{#allParams}}{{^isBodyParam}}{{paramName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}{{^required}}=None{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}):

  1. Then way down after the docstring ends, add in these middle three lines to assign the value of body to the desired parameter name:
    {{#allParams}}
{{#isBodyParam}}
    {{paramName}} = body
{{/isBodyParam}}
    {{^isContainer}}
  1. If you're not already using templates, run the code gen with the -t templates/dir flag. In recent openapi-generator versions, this should pick up just the mustache templates you've provided.
Was this page helpful?
0 / 5 - 0 ratings