Skip to content
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

[BUG][Python-Flask] Missing required argument on PUT, POST, PATCH #1666

Closed
tomghyselinck opened this issue Dec 12, 2018 · 6 comments · Fixed by #20207
Closed

[BUG][Python-Flask] Missing required argument on PUT, POST, PATCH #1666

tomghyselinck opened this issue Dec 12, 2018 · 6 comments · Fixed by #20207

Comments

@tomghyselinck
Copy link
Contributor

tomghyselinck commented Dec 12, 2018

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:

I found a similar issue in connexion:

Suggest a fix

Either:

  1. Workaround as used in Remove self-reference import #1758 (commit 39e4441#diff-23008aab5bc1adc4749f4fa8e9ebb94c):

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

  2. 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.

  3. Keep name body for the (single?) (positional) argument.

@tomghyselinck tomghyselinck changed the title [BUG][Python-Flask] Description [BUG][Python-Flask] Missing required argument on PUT, POST, PATCH Dec 12, 2018
@nathan5280
Copy link

On the suggested fixes in the petstore example.
2. 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.

@BenjaminSchiller
Copy link

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.

@jdeyton
Copy link

jdeyton commented Oct 24, 2019

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.

@SteveHespelt
Copy link

following up on the earlier comment by @nathan5280,
I've found that the OpenAPI-tech 5.0.1 code generator will preserve the x-body-name property if it is NOT a sibling of a $ref usage as mentioned in using-ref. So I have x-body-name as a top-level property for a requestBody type. The generated openapi.yaml has this preserved & the run-time code makes use of this. What's interesting is that the Swagger codegen generated code has 'body' as the formal parameter name while OpenAPI-tech uses the type name to base the parameter name while the Connexion's OpenAPIOperation._get_body_argument() assumes a default of 'body' (overridden by the value of x-body-name in the body's schema, if present).

And this is related to issue 3345 which refers back to this issue.

@srl295
Copy link

srl295 commented Feb 11, 2021

so maybe this is a fourth workaround, but what I see is that the calling code in parameter.py is:

        return function(**kwargs)

… where kwargs={} (for example)

but in my controller there's:

def myfunc(myobj):
   #…
    if connexion.request.is_json:
        myobj = MyObj.from_dict(connexion.request.get_json())  # noqa: E501

so a workaround is to change the signature to def myfunc(myobj=None): - this could be in the template. Should be some way to fix the template so this works by default.

@Johnlon
Copy link

Johnlon commented Feb 5, 2022

The problem is that the existing placement of x-body-name is not compliant with OAS3 and so tools will reject it or drop it on the floor like Openapi Generator.
See spec-first/connexion#1452 which provides support for a valid OAS3 location for this flag.

Once that's incorporated then the setting will be preserved from the source into the generated code base.

jops-wtakase added a commit to jops-wtakase/openapi-generator that referenced this issue Nov 29, 2024
Since Connexion defaults to using 'body' as the argument name for the requestBody, the controller's argument name is adjusted accordingly.
wing328 pushed a commit that referenced this issue Nov 30, 2024
Since Connexion defaults to using 'body' as the argument name for the requestBody, the controller's argument name is adjusted accordingly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
8 participants