'flask errorhandler does not work in gunicorn after introducing flask_restful

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?



Solution 1:[1]

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)

Solution 2:[2]

Had a similar problem (Flask app using Flask-Restplus):

  • with Flask build-in werkzeug, @app.errorhandler decorator works perfectly
  • when run with gunicorn, the default error handler is used (500, Internal Server Error). Solved by deriving Flask-Restplus class and overriding handle_error function to raise the error, letting Flask to handle it.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 masterforker
Solution 2