Issue
I am creating an API using Flask and Flask-RESTful. I wish to parse the body of an incoming request using flask_restful.reqparse.RequestParser()
. Upon receiving an incorrect JSON, I would like to return a 400 Bad Request response. However, my application is instead returning a 500 Internal Server Error response. I thought the RequestParser()
was supposed to handle these responses automatically? Can anyone explain what is going wrong?
Below is the code for the API Resource
from flask_restful import Resource, reqparse
class Foo(Resource):
parser = reqparse.RequestParser()
parser.add_argument("foo",
type=int,
required=True,
action='append',
help="Request body must contain a 'foo' key which comprises a list of IDs, e.g. {'foo': [44, 3213, 532, 4312]}"
)
def get(self):
data = self.parser.parse_args(strict=True)
return {'bar': data['foo']}
When I send a GET request to the API with the body {"err": [3, 4, 1]}
I receive the following 500 Internal Server Error response:
{"message": "Internal Server Error"}
and not the message I specified in the help
parameter. In my logs I also get the following error message:
KeyError: "'foo'"
I know I could wrap the data = self.parser.parse_args(strict=True)
in a try/except KeyError clause and handle the incorrect JSON myself, but I thought that Flask-RESTful would do that for me? What else could I try?
Solution
By defining an APIArgument
class that will be passed to the RequestParser
constructor you can define your own customized response. You also need to pass the bundle_errors = True
to the constructor and configure flask by setting the application configuration key "BUNDLE_ERRORS" to True
See error handling of Request Parsing.
import json
from flask import Flask, Response, abort
from flask_restful import Api, Resource, reqparse
from flask_restful.reqparse import Argument
app = Flask(__name__)
app.config["BUNDLE_ERRORS"] = True
api = Api(app)
class APIArgument(Argument):
def __init__(self, *args, **kwargs):
super(APIArgument, self).__init__(*args, **kwargs)
def handle_validation_error(self, error, bundle_errors):
help_str = "(%s) " % self.help if self.help else ""
msg = "[%s]: %s%s" % (self.name, help_str, str(error))
res = Response(
json.dumps({"message": msg, "code": 400, "status": "FAIL"}),
mimetype="application/json",
status=400,
)
return abort(res)
class Foo(Resource):
parser = reqparse.RequestParser(argument_class=APIArgument, bundle_errors=True)
parser.add_argument(
"foo",
type=int,
action="append",
required=True,
help="Request body must contain a 'foo' key which comprises a list of IDs, e.g. {'foo': [44, 3213, 532, 4312]}",
)
def get(self):
data = self.parser.parse_args(strict=True)
return {'bar': data['foo']}
api.add_resource(Foo, '/')
if __name__ == "__main__":
app.run(port=9000, debug=True)
Answered By - Matteo Pasini
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.