TLDR; What I'm looking to achieve:
Since there's the option to load an universal/app-wide schema in flasgger
, as defined by the template_file
parameter when instantiating Swagger
, how can I automatically validate all data sent to endpoints that have associated flask-restful
Resource
classes when using a universal json schema file?
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"
}
}
}
}
I was originally using individual functions and the @swag_from('myfile.yml', validation=True)
decorator on each function, but for sake of OOP best-practices I wanted to using classes to represent the respective endpoints.
I figured since I loaded the json template_file
when I instantiated Swagger
that the endpoints would be validated against the definitions within that file, but it seems that's not the case for some reason (or I'm doing something wrong).
Can anyone offer some insight on how I can validate all endpoints of my classes against the template_file
definitions? Can it even be done with the current state of the Flasgger
project or is that functionality missing?
Notes:
1. I've created an issue on the Flasgger github repo, which is what I closely mirrored this post after. But, since the repo is pretty uninhabited nowadays I felt it'd be more likely that I'd get an answer here.
2. I'm not looking to use Marshmallow schema, I want to be able to load my swagger schema from the json file when first instantiating Flasgger
and have it applied (have all applicable routes validated based on the Definitions
within the json file) as a whole to all routes.
I guess the problem is in swagger = Swagger(app, template_file='static/Swagger.json')
. Could you please add the option parse
and let me know the behaviour.
swagger = Swagger(app, template_file='static/Swagger.json', parse=True)