Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 748
Leeon LI Avatar asked Nov 10 '22 00:11

Leeon LI


1 Answers

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)
like image 94
masterforker Avatar answered Nov 15 '22 06:11

masterforker