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

RequestBody not passing as Parameter to method #1241

Closed
SouthernYoda opened this issue May 19, 2020 · 9 comments
Closed

RequestBody not passing as Parameter to method #1241

SouthernYoda opened this issue May 19, 2020 · 9 comments

Comments

@SouthernYoda
Copy link

Description

I converted a swagger file to openapi 3.0.0 using https://openapi-converter.herokuapp.com/. All the calls work except the one's using POST and PUT with a requestBody. The python method hasn't been modified since upgrading. Do I need to name the definition I want to pass or does the issue lie somewhere else?

Swagger.yml

      parameters:
        - name: person_id
          in: path
          description: Id the person to update
          required: true
          schema:
            type: integer
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                fname:
                  type: string
                  description: First name of the person
                lname:
                  type: string
                  description: Last name of the person

Method to receive request

def update(person_id, person):

Expected behavior

Successfully updated person

Actual behavior

TypeError: update() missing 1 required positional argument: 'person'

Steps to reproduce

Request-body contents
{
"fname": "John",
"lname": "Doe"
}

Additional info:

Output of the commands:

  • python --version
    Python 3.7.2
  • pip show connexion | grep "^Version\:"
    connexion==2.7.0
@abdullah-abid-dev
Copy link

abdullah-abid-dev commented Aug 4, 2020

Have you tried setting requestBody to true?
i.e.

      requestBody:
        **required: true**
        content:
        ....

@dimitertodorov
Copy link

Also struggling with the same.

post:
      summary: Speak Text to Chromecast or Google Home Device
      operationId: chromecastSpeak
      tags:
        - chromecast
      parameters:
        - in: path
          name: chromecast_id
          schema:
            type: string
          required: true
          description: UUID of the Chromecast device
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SpeechInput"

Method generated:

def chromecast_speak(chromecast_id, speech_input):  # noqa: E501
    """Speak Text to Chromecast or Google Home Device

     # noqa: E501

    :param chromecast_id: UUID of the Chromecast device
    :type chromecast_id: str

Error:

TypeError: chromecast_speak() missing 1 required positional argument: 'speech_input'

@gimbo
Copy link

gimbo commented Mar 4, 2021

I'm seeing the same thing with PATCH — e.g. consider:

    patch:
      ...
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                spec:
                  description: JSONPatch array goes here
              required: [spec]
              additionalProperties: false
      ...

With the above,

  • The receiving function gets an empty body, i.e. {}
  • The connexion.operations.openapi3 logger makes an error-level log entry, saying:

    "Body property 'patch' not defined in body schema"
    (line 322 of connexion.operations.openapi)

Types seem important: the spec property has no type above; if I give it a type of object or number or string, and pass an appropriately-typed value to it, everything works fine (the body parameter shows up as expected and there's no error). If I give it a type of array, it fails as before.

Interestingly, the body does show up at connexion.request.json; I could live with that, were it not for the error message, which I don't want spamming my logs.

For now, I'm dropping the spec envelope entirely, and just passing a JSONPatch document (an array) directly; i.e., this works:

    patch:
      ...
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: array
      ...

(with more info in the spec about the array element schema in practice, of course)

... but it's probably only a matter of time before I hit a case where this isn't an applicable solution.

The fact that types seem involves makes me wonder if this somehow related to #691, #804, #1006.

(Python 3.9.0, connexion 2.7.0)

@sbourdette
Copy link

sbourdette commented Apr 30, 2021

`
post:
operationId: "controllers.identify.updateIdentity"
tags:
- "Faces"
summary: Update Face Identity
description: Update Face Identify
requestBody:
content:
application/json:
schema:
$ref: '../components/prediction.yml'
responses:
'200':
description: "Face"
content:
application/json:
schema:
type: object
required:
- status
- nb
properties:
status:
type: string
enum: ['success', 'error']
nb:
type: integer
name:
type: string

`

def updateIdentity(prediction):
python 3.8
connexion 2.7

TypeError: updateIdentity() missing 1 required positional argument: 'prediction'

Sorry I don't undestand how to quote correctly

@gimbo
Copy link

gimbo commented Apr 30, 2021

@sbourdette You need to wrap the text block with two lines that contain only the string ``` (i.e. three backticks)

So it would look like this in the editor:

```
post:
    operationId: "controllers.identify.updateIdentity"
    tags:
       - "Faces"
    summary: Update Face Identity

    ... and so on...

```

It looks like maybe you tried it with a single backtick? But you need three. You should be able to edit the comment and try again, rather than writing a new one. Hope this helps.

@brandonhs
Copy link

I was struggling with this problem for quite some time and as there is no solution, I feel I could provide some input.

In the documentation, a note can be found titled, Automatic Parameter Handling, stating

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.

In this same section it also states,

Connexion automatically maps the parameters defined in your endpoint specification to arguments of your Python views as named parameters and with value casting whenever possible. All you need to do is define the endpoint’s parameters with matching names with your views arguments.

The solution for a spec like the following,

Configuration file

post:
  ...
  requestBody:
    required: true
    content:
      application/json:
        schema:
          type: object
  ...

would be to make the python code

def do_post(body):
    print(body)

Note the use of the parameter name, body.

Something like

def do_post(not_body):
    print(not_body)

Will not actually work even though the code is functionally the same. A weird quirk of the library in my opinion.

Hopefully this will help someone in the future :-).

@RobbeSneyders
Copy link
Member

Indeed @TheRealJoe24, thanks for pointing this out.

The request body doesn't have a name in OpenAPI 3, so connexion cannot know that you would like to receive the body as person in @SouthernYoda's example. You can fix this by adding x-body-name: "person" to the RequestBody definition in your spec.

You can see an an example of this in one of the examples:
https://github.com/zalando/connexion/blob/c014299435990ff1d4c20596396ca563f7b266b4/examples/openapi3/sqlalchemy/openapi.yaml#L52-L69

https://github.com/zalando/connexion/blob/c014299435990ff1d4c20596396ca563f7b266b4/examples/openapi3/sqlalchemy/app.py#L24

Since this is not a bug and it is documented, I'm closing this issue.

@RobbeSneyders
Copy link
Member

@gimbo your issues seems unrelated. Please create a new issue with a minimal reproducible example.

@chrisinmtown
Copy link
Contributor

This is a late reply to thank @RobbeSneyders for clarifying that simply writing the special parameter name body in the python function will cause connexion to hand it the request body. It's bit cleaner (altho more magical) than using import connexion and body = connexion.request.json in my POST and PUT method handlers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants