Custom error message json object with flask-restful
I disagree with @Miguel on the pertinence of abort()
. Unless you're using Flask to build something other than an HTTP app (with the request/response paradigm), I believe that you should use as much of the HTTPExceptions
as possible (see the werkzeug.exceptions
module). It also means using the aborting mechanism (which is just a shortcut to these exceptions). If instead you opt to explicitly build and return your own errors in views, it leads you into a pattern where you need to check values with a series of if/else/return, which are often unnecessary. Remember, your functions are more than likely operating in the context of a request/response pipeline. Instead of having to travel all the way back to the view before making a decision, just abort the request at the failing point and be done with it. The framework perfectly understands and has contingencies for this pattern. And you can still catch the exception in case you need to (perhaps to supplement it with additional messages, or to salvage the request).
So, similar to @Miguel's but maintaining the intended aborting mechanism:
def json_abort(status_code, data=None):
response = jsonify(data or {'error': 'There was an error'})
response.status_code = status_code
abort(response)
# then in app during a request
def check_unique_username(username):
if UserModel.by__username(username):
json_abort(409, {'error': 'The username is taken'})
def fetch_user(user_id):
try:
return UserModel.get(user_id)
except UserModel.NotFound:
json_abort(404, {'error': 'User not found'})
People tend to overuse abort()
, while in fact it is very simple to generate your own errors. You can write a function that generates custom errors easily, here is one that matches your JSON:
def make_error(status_code, sub_code, message, action):
response = jsonify({
'status': status_code,
'sub_code': sub_code,
'message': message,
'action': action
})
response.status_code = status_code
return response
Then instead of calling abort()
do this:
@route('/')
def my_view_function():
# ...
if need_to_return_error:
return make_error(500, 42, 'You idiots!...', 'redirect...')
# ...
As @Miguel explains, normally you shouldn't use exceptions, just return some error response. However, sometimes you really need an abort mechanism that raises an exception. This may be useful in filter methods, for example. Note that flask.abort accepts a Response object (check this gist):
from flask import abort, make_response, jsonify
json = jsonify(message="Message goes here")
response = make_response(json, 400)
abort(response)
I don't have 50 reputation to comment on @dappiu, so I just have to write a new answer, but it is really related to "Flask-RESTful managed to provide a cleaner way to handle errors" as very poorly documented here
It is such a bad document that took me a while to figure out how to use it. The key is your custom exception must inherit from flask_restful import HTTPException. Please note that you cannot use Python Exception.
from flask_restful import HTTPException
class UserAlreadyExistsError(HTTPException):
pass
custom_errors = {
'UserAlreadyExistsError': {
'message': "A user with that username already exists.",
'status': 409,
}
}
api = Api(app, errors=custom_errors)
Flask-RESTful team has done a good job to make custom exception handling easy but documentation ruined the effort.