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

Data is not automatically validated when using flask-restful & json template_file #342

Closed
caffeinatedMike opened this issue Oct 7, 2019 · 1 comment

Comments

@caffeinatedMike
Copy link

caffeinatedMike commented Oct 7, 2019

TLDR; Expected Behavior:
Since we use a universal/app-wide schema, as defined by the template_file parameter when instantiating Swagger, we should not have to add validation decorators to all flask-restful Resources & their respective methods.


I'm currently designing an API and have run into a situation where when I define my entire schema from a json template file and am utilizing flask-restful Resource classes the data provided in the API calls is not validated.

Posting to /product with a valid payload results in the expected 501 response. But, posting with an invalid payload also results in a 501 response.

Expected Payload:

{
  "id": 0,
  "name": "Toy",
  "photoUrls": [
    "string"
  ],
  "status": "available"
}

Payload that should fail validation:

{
  "id": 0,
  "name": "test",
  "status": "available"
}

Below is a snippet of the Resource class and how I have flasgger configured

# https://github.com/flasgger/flasgger
# pip install flask flasgger flask-restful
from flasgger import Swagger, LazyString, LazyJSONEncoder
from flask import Flask, jsonify, request, url_for
from flask_restful import Api, Resource

app = Flask(__name__)
api = Api(app)

app.json_encoder = LazyJSONEncoder
app.config['SWAGGER'] = {
    'title': 'TestAPI',
    'uiversion': 3,
    'favicon': LazyString(lambda: url_for('static', filename='logo.png')),
    'swagger_ui_css': LazyString(lambda: url_for('static', filename='swagger-ui.css')),
    'specs_route': '/docs/'
}

swagger = Swagger(app, template_file='static/Swagger.json')

class NewProduct(Resource):
    def post(self):
        return '', 501

api.add_resource(NewProduct, '/product')

if __name__ == "__main__":
    app.run(debug=True)

And below is the contents of the Swagger.json file

{
  "swagger": "2.0",
  "info": {
    "description": "",
    "version": "1.0.0",
    "title": "POC for Non-validation Issue",
    "termsOfService": "http://swagger.io/terms/",
    "contact": {
      "email": "testing@abc.com"
    },
    "license": {
      "name": "Apache 2.0",
      "url": "http://www.apache.org/licenses/LICENSE-2.0.html"
    }
  },
  "host": "",
  "basePath": "/",
  "tags": [
    {
      "name": "Product",
      "description": "Operations to manage product info",
      "externalDocs": {
        "description": "Find out more",
        "url": "http://swagger.io"
      }
    }
  ],
  "schemes": [
    "http"
  ],
  "paths": {
    "/product": {
      "post": {
        "tags": [
          "Product"
        ],
        "summary": "Add a new product",
        "description": "",
        "operationId": "addProduct",
        "consumes": [
          "application/json"
        ],
        "produces": [
          "application/json"
        ],
        "parameters": [
          {
            "in": "body",
            "name": "body",
            "description": "",
            "required": true,
            "schema": {
              "$ref": "#/definitions/Product"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Product created"
          },
          "405": {
            "description": "Invalid input"
          },
          "501": {
            "description": "Not Yet Implemented"
          }
        }
      }
    }
  },
  "definitions": {
    "Product": {
      "type": "object",
      "required": [
        "name",
        "photoUrls"
      ],
      "properties": {
        "id": {
          "type": "integer",
          "format": "int64"
        },
        "name": {
          "type": "string",
          "example": "Toy"
        },
        "photoUrls": {
          "type": "array",
          "xml": {
            "name": "photoUrl",
            "wrapped": true
          },
          "items": {
            "type": "string"
          }
        },
        "status": {
          "type": "string",
          "description": "State of availability",
          "enum": [
            "available",
            "pending",
            "sold"
          ]
        }
      },
      "xml": {
        "name": "Toy"
      }
    }
  }
}
@caffeinatedMike
Copy link
Author

caffeinatedMike commented Oct 10, 2019

The original issue is resolved by adding parse=True when instantiating Swagger. While this parameter is covered in the README, I think it would benefit from being elaborated upon a bit more and maybe showing an example that utilizes the functionality.

Now the only issue I'm facing is directly related to #330. Once that is merged my setup works fine.

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

1 participant