I am developing REST API in flask and plan to run it in Gunicorn. In my appliction, an user-defined Exception was handled by by flask errorhandler decorator. It works fine in both flask build-in web server and Gunicorn. The respone can be generated from decorated function. After introducting flask_restful, the build-in server works fine, but in Gunicorn, the respone is always {"message": "Internal Server Error"}.
Here is the source code: myapp.py
from flask import Flask, jsonify, make_response
from flask_restful import Api, Resource
app = Flask(__name__)
api = Api(app)
class OrderNotExistError(Exception):
def __init__(self, order_id):
self.message = 'Order [{order_id}] does not exist.'.format(order_id=order_id)
@app.errorhandler(OrderNotExistError)
def order_not_exist(error):
return make_response(jsonify({'message': error.message}), 404)
class OrderAPI(Resource):
def get(self, order_id):
raise OrderNotExistError(order_id)
api.add_resource(OrderAPI, '/orders/<int:order_id>', endpoint='order')
@app.route("/o/<int:order_id>")
def get_order(order_id):
raise OrderNotExistError(order_id)
if __name__ == '__main__':
app.debug = True
app.run()
Run it in Gunicorn: gunicorn -w4 -b0.0.0.0:8000 myapp:app
Access "http://127.0.0.1:8000/o/123"
It response:
{"message": "Order [123] does not exist."}.
The error handler works fine.
Access "http://127.0.0.1:8000/orders/123"
It Response:
{"message": "Internal Server Error"}.
Seems the error handler does not work.
When run it in flask build-in server, the problem does not occur.
Does anybody meet the same problem? Is this a bug in flask_restful or Gunicorn? How to deal with this problem?
This is because there are two levels of error handlers one at the app level and one at the api level. You are making a direct call to the api and therefore the app does not see this. (This explains why the exception is caught for the route added through app.route and not for the one added through api.add_resource).
To catch this error, you need to override Werkzeug's exceptions which is what flask-restful uses. The following code should fix it:
errors={
'InternalServerError': {
'status': 500,
'message': 'Internal Server Error'
},
}
api = Api(app, errors=errors)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With