connexion icon indicating copy to clipboard operation
connexion copied to clipboard

required: false in POST body not honored? I think?

Open mmattb opened this issue 3 years ago • 6 comments

Description

---
openapi: "3.0.3"
info:
  description: "Some service"
  version: "0"
  title: "hello"
  contact:
    email: "[email protected]"
servers:
  - url: http://hello.com/1
paths:
  /hello:
    post:
      summary: "hello"
      description: "hello"
      operationId: blah.endpoint
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: array
      responses:
        4XX:
          description: "Failure"
        200:
          description: "Success"

Note the required: false property on the body clause. My understanding from the Swagger3 spec is that this indicates that the body can be omitted from the request. However, I get an error if I don't also include the x-nullable: true property. Shouldn't required: false be treated the same as x-nullable?

Specifically, I get:

http://127.0.0.1:8765/1/hello validation error: None is not of type 'array'
127.0.0.1 - - [05/Nov/2020 20:56:33] "POST /1/hello HTTP/1.1" 400 -

When I call it with this: curl -v -X POST http://127.0.0.1:8765/1/hello

I get the same result with Python's requests.post with data=None.

I may be misunderstanding what curl and requests do with a null data value, but I think that means "no body supplied"?

I'm thinking is_null_value_valid should be set to True on the validator when required: false is provided.

Expected behaviour

That the endpoint func will be called with an empty body, since it is allowed by the Swagger definition, and that is what I'm passing.

Actual behaviour

400, and a nondescript error message that requires spelunking the code to understand

Steps to reproduce

See above

Additional info:

Output of the commands: Python 3.7.9 Version: 2.7.0

mmattb avatar Nov 06 '20 05:11 mmattb

I get the same problem with type: object.

flask-pro avatar Feb 06 '21 14:02 flask-pro

Thanks for the report @mmattb, I can indeed reproduce.

I quickly looked into the underlying issue, but it does not seem to be a quick fix. is_null_value_valid is indeed set to False when creating the RequestBodyValidator here: https://github.com/zalando/connexion/blob/f45ef0e5aefbce100e0220dc698dd61768c654d3/connexion/operations/abstract.py#L435-L437 Unfortunately, it's not as easy as just changing the is_nullable function since the self.body_definition only contains the schema of the body, not the full definition with the required attribute.

You can work around this for now with x-nullable:

application/json:
  schema:
    type: array
    x-nullable: true

RobbeSneyders avatar Jul 19 '21 21:07 RobbeSneyders

Hi, I tried this workaround but I'm receiving another error:

{
    "detail": "The browser (or proxy) sent a request that this server could not understand.",
    "status": 400,
    "title": "Bad Request",
    "type": "about:blank"
}

This is the openapi spec that I've used:

 requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InputBody'     

components:
  schemas:
    InputBody:
      type: object
      x-nullable: true
      properties:
        tags:
          type: array
          items:
            $ref: '#/components/schemas/TagInput'

Am I understanding this workaround incorrectly???

20Aditya avatar Mar 04 '22 06:03 20Aditya

@20Aditya can you please post a minimal working example? Spec, python code and curl request.

RobbeSneyders avatar Mar 04 '22 08:03 RobbeSneyders

Hi, here are the details:

Openapi Spec

openapi: "3.0.1"
info:
  title: Store Service
  description: "Store Service"
  contact:
    name: ""
  version: 1.0.0
servers:
- url: http://127.0.0.1:9080/v1/
tags:
- name: Store
paths:
  /store:
    post:
      tags:
      - Store
      summary: API Stores some data
      requestBody:
        content:
          application/json:
            schema:
              x-nullable: true
              $ref: '#/components/schemas/InputBody'
      responses:
        202:
          description: Success
      x-codegen-request-body-name: body

components:
  schemas:
    InputBody:
      type: object
      x-nullable: true
      properties:
        tags:
          type: array
          x-nullable: true
          items:
            $ref: '#/components/schemas/TagInput'
    TagInput:
      type: object
      x-nullable: true
      properties:
        tagGroup:
          type: string
          example: "0010"
          nullable: true

I'm using Openapi code-generator to generate the api code using cli:

java -cp openapi-generator-cli-4.0.0.jar org.openapitools.codegen.OpenAPIGenerator generate -i openapi.yaml -g python-flask -o ' + OUT_DIR  --model-package model

Note the x-nullable: true flag that I've given in the component schemas under type: object

When I hit the endpoint with this curl request: curl -X POST 'localhost:9080/v1/store' -H 'Content-Type: application/json'

I get the error that I've described above:

{
    "detail": "The browser (or proxy) sent a request that this server could not understand.",
    "status": 400,
    "title": "Bad Request",
    "type": "about:blank"
}

Versions

"Flask==1.1.2",
"connexion==2.0.0",
"waitress==1.3.0",
"Werkzeug==0.16.0",
"swagger-ui-bundle==0.0.2",
"python_dateutil==2.6.0",
"openapi_spec_validator==0.2.9",
"jsonschema==2.6.0",

Please let me know if any further information is required.

20Aditya avatar Mar 04 '22 09:03 20Aditya

I am seeing very similar behavior w/ Connexion 2.13.0 and POST requests with required: false bodies. I couldn't make it work with x-nullable: true and my behavior is slightly different. Even if the body is in fact null/none, Connexion seems to be getting an empty string and responds with:

code=400, description="Bad request: '' is not of type 'object'."

I am using Connexion with aiohttp, fwiw. Minimal example here https://github.com/rschmied/conex

Verification:

  • pip install connexion==2.11.2 POST with empty body --> works
  • pip install connexion==2.13.0 POST with empty body --> '' is not of type 'object'.

First is with 2.11.2, second with 2.13.0:

$ curl -X POST http://localhost:8080/api/hello
{"result": "empty"}
$ curl -X POST http://localhost:8080/api/hello
{"type": "about:blank", "title": "Bad Request", "detail": "'' is not of type 'object'", "status": 400}
$

rschmied avatar Mar 29 '22 20:03 rschmied