Reputation: 4604
I am trying to use global error handlers(app_errorhandler
) in my APIs but I am getting some problems.
I have a blueprint for errors where I define global errors defined as:
from werkzeug.exceptions import NotFound
from flask_app.errors import error_bp
@error_bp.app_errorhandler(NotFound)
def not_found_error(error):
return "Error 404", 404
and this works fine for all app routes, but not for APIs created by flask_restplus
nor flask_restful
(tried both). When I try to raise NotFound
in them I get:
"The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again. You have requested this URI [/user/info/1/] but did you mean /user/info// or /user/edit// or /user/login ?"
When I define a errorhandler
in my API as:
@user_api.errorhandler(NotFound)
def new_error(error):
return "Error handler in API 404"
It does not use this errorhandler
in API but the global one(why? how?), so I got a way to use app_errorhandler
but this is not a solution as I do not want to define for every API an errorhandler
if I have global set up. All my APIs are created using the blueprint they are in.
So my question is: How do I use the app_errorhandler
in APIs without defining errorhandler
in every API?
Answers can be flask_restplus or flask_restful because I have no problem with switching from one to the other. Thanks in advance.
NOTE:
There are a lot of workarounds but I think that api
s should be able to use app
s errors by default because blueprints
can use them and api
s inherit Blueprints
Project structure and code as per Mehdi Sadeghi
request:
.
|____flask_test_app
| |____errors
| |___ __init__.py
| |___ handlers.py
| |____test_found
| |___ __init__.py
| |___ apis.py
| |_____ __init__.py
__init__.py
:
from flask import Flask
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config_name)
from .errors import error_bp
app.register_blueprint(error_bp)
from .test_found import test_found
app.register_blueprint(test_found)
return app
errors.__init__.py
:
from flask import Blueprint
error_bp = Blueprint('error_bp', import_name='error_bp')
from flask_test_app.errors import handlers
errors.handlers.py
:
from werkzeug.exceptions import NotFound
from flask_test_app.errors import error_bp
@error_bp.app_errorhandler(NotFound)
def not_found_error(error):
return "Error 404", 404
test_found.__init__py
:
from flask import Blueprint
from flask_restplus import Api
test_found = Blueprint('test_found', import_name='test_found',
url_prefix='/test_found')
test_found_api = Api(test_found)
from flask_test_app.test_found import apis
test_found.apis.py
:
from flask_restplus import Resource
from flask_test_app.test_found import test_found, test_found_api
from werkzeug.exceptions import NotFound
@test_found.route('/test_not_found', methods=['GET'])
def test_not_found():
raise NotFound
return "Not found does not work"
class TestAPINotFound(Resource):
def get(self):
raise NotFound
return "TEST NOT FOUND FOR APIs"
test_found_api.add_resource(TestAPINotFound,
'/test_api_not_found',
endpoint='user_test')
Upvotes: 3
Views: 3016
Reputation: 5154
In flask-restful, as described in the docs you can pass an errors
dictionary to the api and customize the returned message:
errors = {
'NotFound': {
'message': "Something is missing.",
'status': 404,
}
}
api = Api(app, errors=errors)
Moreover it provides flask_restful.abort
that you can use anywhere in your API:
class HelloWorld(Resource):
def get(self):
if not self.has_permission():
return flask_restful.abort(403)
return {'hello': 'world'}
You can also catch your exceptions such as NotFound
and use flask_restful.abort
as above.
However, if you really need to customize the error handling you can subclass the Api
and implement your own error handing before calling flask_restful.abort
:
class CustomApi(Api):
def handle_error(self, e):
# Do something and then abort
flask_restful.abort('some error code...', 'error message')
api = CustomApi(app, errors=errors)
Upvotes: 3