flask-restx
flask-restx copied to clipboard
@api.expect decorator does not validate DateTime fields
Code
import json
import requests
from flask import Flask, request
from flask_restx import Api, Resource, fields
from jsonschema import FormatChecker
app = Flask(__name__)
api_restplus = Api(
app,
# format_checker=FormatChecker(formats=("date",)),
)
myApi_arguments_fields = api_restplus.model("payload", {"begin_date": fields.Date()})
@api_restplus.route("/myApi")
class MyApi(Resource):
@api_restplus.expect(myApi_arguments_fields, validate=True)
def post(self):
_ = json.loads(request.data)
return None
if __name__ == "__main__":
app.run(port=5001)
Repro Steps
Execute:
% curl -X POST "http://127.0.0.1:5001/myApi" -H "accept: application/json" -H "Content-Type: application/json" -d "{\"begin_date\":\"test\"}
Expected Behavior
I would expect the following response:
{"errors": {"begin_date": "'test' is not a 'date'"}, "message": "Input payload validation failed"}
Actual Behavior
Even though the begin_date
does not conform iso8601 format, I don't get a validation error. The input passes validation just fine.
Environment
- Python 3.7
- Flask 1.1.2
- Flask-RESTX 0.2.0
- Other installed Flask extensions: Flask-MonitoringDashboard 3.1.0
Additional Context
The bug is fixable by uncommenting the following line in my code example:
# format_checker=FormatChecker(formats=("date",)),
An issue about this bug has been open at Flask-RESTPlus since 2016: noirbizarre/flask-restplus#204.
I feel like this is a bug, as having a fields.Date
functionality implies that validation will take place, but it actually doesn't. This behavior seems to be sort-of documented, but its documentation is extremely tucked away and not explicit, and this whole problem gave me quite a headache. I feel like either the FormatChecker
functionality should be turned on by default, a warning / exception should be raised if no FormatChecker
is provided but flask_restx.fields.Date
is initiated, or at least flask_restx.fields.Date
/ flask_restx.fields.DateTime
's documentation should be improved.
Also, the api.payload doesn't match the model definition. Date fields a rendered as String and not as Date
Same for me :(
I'm currently using a simple regex but it's very flimsy as it can't validate all the iso8601 patterns:
iso8601_regex = r'^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:\d{2})$'
model = api.model('Model', {
'timepoint': fields.String(required=True, description='Timepoint in ISO 8601 format', pattern=iso8601_regex),
# Other fields...
})