swagger-api / swagger-codegen

swagger-codegen contains a template-driven engine to generate documentation, API clients and server stubs in different languages by parsing your OpenAPI / Swagger definition.
http://swagger.io
Apache License 2.0
16.98k stars 6.03k forks source link

python flask output not validating properly #9162

Open shockey opened 5 years ago

shockey commented 5 years ago

From @alexfrieden on February 7, 2019 20:35

Q&A (please complete the following information)

Content & configuration

Example Swagger/OpenAPI definition: ```yaml # your YAML here --- swagger: "2.0" info: description: "This is a sample server Petstore server. You can find out more about\ \ Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net,\ \ #swagger](http://swagger.io/irc/). For this sample, you can use the api\ \ key `special-key` to test the authorization filters." version: "1.0.0" title: "Swagger Petstore" termsOfService: "http://swagger.io/terms/" contact: email: "apiteam@swagger.io" license: name: "Apache 2.0" url: "http://www.apache.org/licenses/LICENSE-2.0.html" #host: "petstore.swagger.io" basePath: "/v2" tags: - name: "pet" description: "Everything about your Pets" externalDocs: description: "Find out more" url: "http://swagger.io" - name: "store" description: "Access to Petstore orders" - name: "user" description: "Operations about user" externalDocs: description: "Find out more about our store" url: "http://swagger.io" schemes: - "https" - "http" paths: /pet: post: tags: - "pet" summary: "Add a new pet to the store" description: "" operationId: "add_pet" consumes: - "application/json" - "application/xml" produces: - "application/xml" - "application/json" parameters: - in: "body" name: "body" description: "Pet object that needs to be added to the store" required: true schema: $ref: "#/definitions/Pet" responses: 200: description: "all good" 405: description: "Invalid input" security: - petstore_auth: - "write:pets" - "read:pets" x-swagger-router-controller: "swagger_server.controllers.pet_controller" put: tags: - "pet" summary: "Update an existing pet" description: "" operationId: "update_pet" consumes: - "application/json" - "application/xml" produces: - "application/xml" - "application/json" parameters: - in: "body" name: "body" description: "Pet object that needs to be added to the store" required: true schema: $ref: "#/definitions/Pet" responses: 400: description: "Invalid ID supplied" 404: description: "Pet not found" 405: description: "Validation exception" security: - petstore_auth: - "write:pets" - "read:pets" x-swagger-router-controller: "swagger_server.controllers.pet_controller" /pet/findByStatus: get: tags: - "pet" summary: "Finds Pets by status" description: "Multiple status values can be provided with comma separated strings" operationId: "find_pets_by_status" produces: - "application/xml" - "application/json" parameters: - name: "status" in: "query" description: "Status values that need to be considered for filter" required: true type: "array" items: type: "string" default: "available" enum: - "available" - "pending" - "sold" collectionFormat: "multi" responses: 200: description: "successful operation" schema: type: "array" items: $ref: "#/definitions/Pet" 400: description: "Invalid status value" security: - petstore_auth: - "write:pets" - "read:pets" x-swagger-router-controller: "swagger_server.controllers.pet_controller" /pet/findByTags: get: tags: - "pet" summary: "Finds Pets by tags" description: "Muliple tags can be provided with comma separated strings. Use\ \ tag1, tag2, tag3 for testing." operationId: "find_pets_by_tags" produces: - "application/xml" - "application/json" parameters: - name: "tags" in: "query" description: "Tags to filter by" required: true type: "array" items: type: "string" collectionFormat: "multi" responses: 200: description: "successful operation" schema: type: "array" items: $ref: "#/definitions/Pet" 400: description: "Invalid tag value" security: - petstore_auth: - "write:pets" - "read:pets" deprecated: true x-swagger-router-controller: "swagger_server.controllers.pet_controller" /pet/{petId}: get: tags: - "pet" summary: "Find pet by ID" description: "Returns a single pet" operationId: "get_pet_by_id" produces: - "application/xml" - "application/json" parameters: - name: "petId" in: "path" description: "ID of pet to return" required: true type: "integer" format: "int64" responses: 200: description: "successful operation" schema: $ref: "#/definitions/Pet" 400: description: "Invalid ID supplied" 404: description: "Pet not found" security: - api_key: [] x-swagger-router-controller: "swagger_server.controllers.pet_controller" post: tags: - "pet" summary: "Updates a pet in the store with form data" description: "" operationId: "update_pet_with_form" consumes: - "application/x-www-form-urlencoded" produces: - "application/xml" - "application/json" parameters: - name: "petId" in: "path" description: "ID of pet that needs to be updated" required: true type: "integer" format: "int64" - name: "name" in: "formData" description: "Updated name of the pet" required: false type: "string" - name: "status" in: "formData" description: "Updated status of the pet" required: false type: "string" responses: 405: description: "Invalid input" security: - petstore_auth: - "write:pets" - "read:pets" x-swagger-router-controller: "swagger_server.controllers.pet_controller" delete: tags: - "pet" summary: "Deletes a pet" description: "" operationId: "delete_pet" produces: - "application/xml" - "application/json" parameters: - name: "api_key" in: "header" required: false type: "string" - name: "petId" in: "path" description: "Pet id to delete" required: true type: "integer" format: "int64" responses: 400: description: "Invalid ID supplied" 404: description: "Pet not found" security: - petstore_auth: - "write:pets" - "read:pets" x-swagger-router-controller: "swagger_server.controllers.pet_controller" /pet/{petId}/uploadImage: post: tags: - "pet" summary: "uploads an image" description: "" operationId: "upload_file" consumes: - "multipart/form-data" produces: - "application/json" parameters: - name: "petId" in: "path" description: "ID of pet to update" required: true type: "integer" format: "int64" - name: "additionalMetadata" in: "formData" description: "Additional data to pass to server" required: false type: "string" - name: "file" in: "formData" description: "file to upload" required: false type: "file" responses: 200: description: "successful operation" schema: $ref: "#/definitions/ApiResponse" security: - petstore_auth: - "write:pets" - "read:pets" x-swagger-router-controller: "swagger_server.controllers.pet_controller" /store/inventory: get: tags: - "store" summary: "Returns pet inventories by status" description: "Returns a map of status codes to quantities" operationId: "get_inventory" produces: - "application/json" parameters: [] responses: 200: description: "successful operation" schema: type: "object" additionalProperties: type: "integer" format: "int32" security: - api_key: [] x-swagger-router-controller: "swagger_server.controllers.store_controller" /store/order: post: tags: - "store" summary: "Place an order for a pet" description: "" operationId: "place_order" produces: - "application/xml" - "application/json" parameters: - in: "body" name: "body" description: "order placed for purchasing the pet" required: true schema: $ref: "#/definitions/Order" responses: 200: description: "successful operation" schema: $ref: "#/definitions/Order" 400: description: "Invalid Order" x-swagger-router-controller: "swagger_server.controllers.store_controller" /store/order/{orderId}: get: tags: - "store" summary: "Find purchase order by ID" description: "For valid response try integer IDs with value >= 1 and <= 10.\ \ Other values will generated exceptions" operationId: "get_order_by_id" produces: - "application/xml" - "application/json" parameters: - name: "orderId" in: "path" description: "ID of pet that needs to be fetched" required: true type: "integer" maximum: 10 minimum: 1 format: "int64" responses: 200: description: "successful operation" schema: $ref: "#/definitions/Order" 400: description: "Invalid ID supplied" 404: description: "Order not found" x-swagger-router-controller: "swagger_server.controllers.store_controller" delete: tags: - "store" summary: "Delete purchase order by ID" description: "For valid response try integer IDs with positive integer value.\ \ Negative or non-integer values will generate API errors" operationId: "delete_order" produces: - "application/xml" - "application/json" parameters: - name: "orderId" in: "path" description: "ID of the order that needs to be deleted" required: true type: "integer" minimum: 1 format: "int64" responses: 400: description: "Invalid ID supplied" 404: description: "Order not found" x-swagger-router-controller: "swagger_server.controllers.store_controller" /user: post: tags: - "user" summary: "Create user" description: "This can only be done by the logged in user." operationId: "create_user" produces: - "application/xml" - "application/json" parameters: - in: "body" name: "body" description: "Created user object" required: true schema: $ref: "#/definitions/User" responses: default: description: "successful operation" x-swagger-router-controller: "swagger_server.controllers.user_controller" /user/createWithArray: post: tags: - "user" summary: "Creates list of users with given input array" description: "" operationId: "create_users_with_array_input" produces: - "application/xml" - "application/json" parameters: - in: "body" name: "body" description: "List of user object" required: true schema: type: "array" items: $ref: "#/definitions/User" responses: default: description: "successful operation" x-swagger-router-controller: "swagger_server.controllers.user_controller" /user/createWithList: post: tags: - "user" summary: "Creates list of users with given input array" description: "" operationId: "create_users_with_list_input" produces: - "application/xml" - "application/json" parameters: - in: "body" name: "body" description: "List of user object" required: true schema: type: "array" items: $ref: "#/definitions/User" responses: default: description: "successful operation" x-swagger-router-controller: "swagger_server.controllers.user_controller" /user/login: get: tags: - "user" summary: "Logs user into the system" description: "" operationId: "login_user" produces: - "application/xml" - "application/json" parameters: - name: "username" in: "query" description: "The user name for login" required: true type: "string" - name: "password" in: "query" description: "The password for login in clear text" required: true type: "string" responses: 200: description: "successful operation" headers: X-Rate-Limit: type: "integer" format: "int32" description: "calls per hour allowed by the user" X-Expires-After: type: "string" format: "date-time" description: "date in UTC when token expires" schema: type: "string" 400: description: "Invalid username/password supplied" x-swagger-router-controller: "swagger_server.controllers.user_controller" /user/logout: get: tags: - "user" summary: "Logs out current logged in user session" description: "" operationId: "logout_user" produces: - "application/xml" - "application/json" parameters: [] responses: default: description: "successful operation" x-swagger-router-controller: "swagger_server.controllers.user_controller" /user/{username}: get: tags: - "user" summary: "Get user by user name" description: "" operationId: "get_user_by_name" produces: - "application/xml" - "application/json" parameters: - name: "username" in: "path" description: "The name that needs to be fetched. Use user1 for testing. " required: true type: "string" responses: 200: description: "successful operation" schema: $ref: "#/definitions/User" 400: description: "Invalid username supplied" 404: description: "User not found" x-swagger-router-controller: "swagger_server.controllers.user_controller" put: tags: - "user" summary: "Updated user" description: "This can only be done by the logged in user." operationId: "update_user" produces: - "application/xml" - "application/json" parameters: - name: "username" in: "path" description: "name that need to be updated" required: true type: "string" - in: "body" name: "body" description: "Updated user object" required: true schema: $ref: "#/definitions/User" responses: 400: description: "Invalid user supplied" 404: description: "User not found" x-swagger-router-controller: "swagger_server.controllers.user_controller" delete: tags: - "user" summary: "Delete user" description: "This can only be done by the logged in user." operationId: "delete_user" produces: - "application/xml" - "application/json" parameters: - name: "username" in: "path" description: "The name that needs to be deleted" required: true type: "string" responses: 400: description: "Invalid username supplied" 404: description: "User not found" x-swagger-router-controller: "swagger_server.controllers.user_controller" securityDefinitions: petstore_auth: type: "oauth2" authorizationUrl: "http://petstore.swagger.io/oauth/dialog" flow: "implicit" scopes: write:pets: "modify pets in your account" read:pets: "read your pets" api_key: type: "apiKey" name: "api_key" in: "header" definitions: Order: type: "object" properties: id: type: "integer" format: "int64" petId: type: "integer" format: "int64" quantity: type: "integer" format: "int32" shipDate: type: "string" format: "date-time" status: type: "string" description: "Order Status" enum: - "placed" - "approved" - "delivered" complete: type: "boolean" default: false xml: name: "Order" example: petId: 6 quantity: 1 id: 0 shipDate: "2000-01-23T04:56:07.000+00:00" complete: false status: "placed" Category: type: "object" properties: id: type: "integer" format: "int64" name: type: "string" xml: name: "Category" example: name: "name" id: 6 User: type: "object" properties: id: type: "integer" format: "int64" username: type: "string" firstName: type: "string" lastName: type: "string" email: type: "string" password: type: "string" phone: type: "string" userStatus: type: "integer" format: "int32" description: "User Status" xml: name: "User" example: firstName: "firstName" lastName: "lastName" password: "password" userStatus: 6 phone: "phone" id: 0 email: "email" username: "username" Tag: type: "object" properties: id: type: "integer" format: "int64" name: type: "string" xml: name: "Tag" example: name: "name" id: 1 Pet: type: "object" required: - "name" - "photoUrls" properties: id: type: "integer" format: "int64" category: $ref: "#/definitions/Category" name: type: "string" example: "doggie" photoUrls: type: "array" xml: name: "photoUrl" wrapped: true items: type: "string" tags: type: "array" xml: name: "tag" wrapped: true items: $ref: "#/definitions/Tag" status: type: "string" description: "pet status in the store" enum: - "available" - "pending" - "sold" xml: name: "Pet" example: photoUrls: - "photoUrls" - "photoUrls" name: "doggie" id: 0 category: name: "name" id: 6 tags: - name: "name" id: 1 - name: "name" id: 1 status: "available" ApiResponse: type: "object" properties: code: type: "integer" format: "int32" type: type: "string" message: type: "string" example: code: 0 type: "type" message: "message" externalDocs: description: "Find out more about Swagger" url: "http://swagger.io" ``` Swagger-Editor configuration options: ```js SwaggerEditor({ // your config options here }) ``` ``` ?yourQueryStringConfig ``` ### Describe the bug you're encountering

To reproduce...

Steps to reproduce the behavior:

  1. Go to '...' generate server
  2. Click on '....' python-flask export it virtualenv env pip install -r requirements.txt python -m swagger_server/ go to post to pets using example
  3. Scroll down to '....'
  4. See error
    Traceback (most recent call last):
    File "/Users/afrieden/Downloads/python-flask-server-final/env/lib/python3.7/site-packages/flask/app.py", line 2292, in wsgi_app
    response = self.full_dispatch_request()
    File "/Users/afrieden/Downloads/python-flask-server-final/env/lib/python3.7/site-packages/flask/app.py", line 1815, in full_dispatch_request
    rv = self.handle_user_exception(e)
    File "/Users/afrieden/Downloads/python-flask-server-final/env/lib/python3.7/site-packages/flask/app.py", line 1718, in handle_user_exception
    reraise(exc_type, exc_value, tb)
    File "/Users/afrieden/Downloads/python-flask-server-final/env/lib/python3.7/site-packages/flask/_compat.py", line 35, in reraise
    raise value
    File "/Users/afrieden/Downloads/python-flask-server-final/env/lib/python3.7/site-packages/flask/app.py", line 1813, in full_dispatch_request
    rv = self.dispatch_request()
    File "/Users/afrieden/Downloads/python-flask-server-final/env/lib/python3.7/site-packages/flask/app.py", line 1799, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
    File "/Users/afrieden/Downloads/python-flask-server-final/env/lib/python3.7/site-packages/connexion/decorators/decorator.py", line 66, in wrapper
    response = function(request)
    File "/Users/afrieden/Downloads/python-flask-server-final/env/lib/python3.7/site-packages/connexion/decorators/validation.py", line 122, in wrapper
    response = function(request)
    File "/Users/afrieden/Downloads/python-flask-server-final/env/lib/python3.7/site-packages/connexion/decorators/validation.py", line 293, in wrapper
    return function(request)
    File "/Users/afrieden/Downloads/python-flask-server-final/env/lib/python3.7/site-packages/connexion/decorators/decorator.py", line 42, in wrapper
    response = function(request)
    File "/Users/afrieden/Downloads/python-flask-server-final/env/lib/python3.7/site-packages/connexion/decorators/parameter.py", line 218, in wrapper
    return function(**kwargs)
    File "/Users/afrieden/Downloads/python-flask-server-final/swagger_server/controllers/pet_controller.py", line 20, in add_pet
    body = Pet.from_dict(connexion.request.get_json())  # noqa: E501
    File "/Users/afrieden/Downloads/python-flask-server-final/swagger_server/models/pet.py", line 70, in from_dict
    return util.deserialize_model(dikt, cls)
    File "/Users/afrieden/Downloads/python-flask-server-final/swagger_server/util.py", line 111, in deserialize_model
    setattr(instance, attr, _deserialize(value, attr_type))
    File "/Users/afrieden/Downloads/python-flask-server-final/swagger_server/util.py", line 26, in _deserialize
    elif type(klass) == typing.GenericMeta:
    AttributeError: module 'typing' has no attribute 'GenericMeta'

    Expected behavior

    It seems that this is getting some strange errors of Expect it to run through and validate the json that was entered for a model

Screenshots

Additional context or thoughts

Copied from original issue: swagger-api/swagger-editor#1942

shockey commented 5 years ago

Hi @alexfrieden, it looks like you're seeing an error from a generated Python server.

This is a Codegen error, so I'm going to move it there for you.

alexfrieden commented 5 years ago

The issue seems to be a problem with connexion and the utils.py. From the following issue: https://github.com/zalando/connexion/issues/739 (copy and pasted in)

Ok, if anyone have the same problem, you can edit util.py in the following way:

Change

elif type(klass) == typing.GenericMeta:
    if klass.__extra__ == list:
        return _deserialize_list(data, klass.__args__[0])
    if klass.__extra__ == dict:
        return _deserialize_dict(data, klass.__args__[1])

In util.py , to

elif hasattr(klass, '__origin__'):
    if klass.__origin__ == list:
        return _deserialize_list(data, klass.__args__[0])
    if klass.__origin__ == dict:
        return _deserialize_dict(data, klass.__args__[1])

I used some google-fu and found this answer in stack overflow