swagger-api/swagger-codegen

[Python] auto generated python-flask server fails to map in-body parameter name

Open

#6257 opened on Aug 7, 2017

View on GitHub
 (5 comments) (0 reactions) (0 assignees)HTML (12,701 stars) (5,474 forks)batch import
Issue: BugServer: Pythonhelp wanted

Description

Preface

When using a body parameter, the name is only used for documentation purposes OpenAPI 2.0 specification:

[...] The name of the body parameter has no effect on the parameter itself and is used for documentation purposes only. [...]

According to the Connexion documentatoin it makes a name sanitation for parameter names:

The names of query and form parameters, as well as the name of the body parameter are sanitized by removing characters that are not allowed in Python symbols.

With the following command:

re.sub('^[^a-zA-Z_]+', '', re.sub('[^0-9a-zA-Z_]', '', PARAMETER_NAME))
Description

Swagger converts underscored in-body property name, when generating python-flask server, to the CamelCase, so connexion can not map it. (The simple swagger.yaml to reproduce the issue is in this Gist)

So the following definition

 parameters:
      - in: body
        name: test_object
        description: object that fails to map
        schema:
          $ref: '#/definitions/TestObject'

Will lead to the following code:

def endpoint_post(testObject = None) -> str:
    return 'do some magic! '

As you can see it turns test_object to testObject. But when mapping the parameters, connexion would expect test_object, since it is a result of

re.sub('^[^a-zA-Z_]+', '', re.sub('[^0-9a-zA-Z_]', '', 'test_object'))

As the result the server accepts the correct request, but fails to map it because of the bad variable name.

Swagger-codegen version

The online version of the swagger editor, and generator (through the editor menu) on https://app.swaggerhub.com

Swagger declaration file content or url

this yaml is a simple reproduction example

Command line used for generation

none - generated via swaggerhub

Steps to reproduce

Tested with Python 3.5.2, Flask 0.12.2 and connexion 1.1.13 on Ubuntu 16.04

  1. generate online the python-flask server using this yaml
  2. Edit default_controller.py in ./controllers to display the output of the request (for the debug purposes) e.g. like this:
def endpoint_post(testObject = None) -> str:
    return 'do some magic! ' + str(testObject)
  1. run it with: $> python app.py
  2. Get sure the request validation works by sending from another terminal a bad request (property_six instead of property_one) via curl:
$> curl -X POST -H "Content-Type: application/json" --data '{"property_six":"ONE", "property_two":"TWO", "property_three":"THREE"}' http://127.0.0.1:8080/endpoint

validation works:

{
  "detail": "'property_one' is a required property",
  "status": 400,
  "title": "Bad Request",
  "type": "about:blank"
}
  1. Send now the correct request via curl:
$> curl -X POST -H "Content-Type: application/json" --data '{"property_one":"ONE", "property_two":"TWO", "property_three":"THREE"}' http://127.0.0.1:8080/endpoint

The request was accepted, but not mapped to testObject – it is None (default value)

"do some magic! None"
  1. Rename auto generated testObject in the default_controller.py to test_object to get sure, it's a name issue.
def endpoint_post(test_object = None) -> str:
    return 'do some magic! ' + str(test_object)
  1. Send again the correct request via curl:
$> curl -X POST -H "Content-Type: application/json" --data '{"property_one":"ONE", "property_two":"TWO", "property_three":"THREE"}' http://127.0.0.1:8080/endpoint

et voila: the mapping works like it should:

"do some magic! {'property_one': 'ONE', 'property_two': 'TWO', 'property_three': 'THREE'}"
Related issues/PRs

not seen before

Suggest a fix/enhancement

The problem is caused trhough the name conversion. Maybe when generating this part of the code the name conversion should be similar to

re.sub('^[^a-zA-Z_]+', '', re.sub('[^0-9a-zA-Z_]', '', PARAMETER_NAME))

Contributor guide