Error handling

HTTPException handling

Werkzeug HTTPException are automatically properly seriliazed reusing the description attribute.

from werkzeug.exceptions import BadRequest
raise BadRequest()

will return a 400 HTTP code and output

{
    "message": "The browser (or proxy) sent a request that this server could not understand."
}

whereas this:

from werkzeug.exceptions import BadRequest
raise BadRequest('My custom message')

will output

{
    "message": "My custom message"
}

You can attach extras attributes to the output by providing a data attribute to your exception.

from werkzeug.exceptions import BadRequest
e = BadRequest('My custom message')
e.data = {'custom': 'value'}
raise e

will output

{
    "message": "My custom message",
    "custom": "value"
}

The Flask abort helper

The abort helper properly wraps errors into a HTTPException so it will have the same behavior.

from flask import abort
abort(400)

will return a 400 HTTP code and output

{
    "message": "The browser (or proxy) sent a request that this server could not understand."
}

whereas this:

from flask import abort
abort(400, 'My custom message')

will output

{
    "message": "My custom message"
}

The Flask-RESTX abort helper

The errors.abort() and the Namespace.abort() helpers works like the original Flask flask.abort() but it will also add the keyword arguments to the response.

from flask_restx import abort
abort(400, custom='value')

will return a 400 HTTP code and output

{
    "message": "The browser (or proxy) sent a request that this server could not understand.",
    "custom": "value"
}

whereas this:

from flask import abort
abort(400, 'My custom message', custom='value')

will output

{
    "message": "My custom message",
    "custom": "value"
}

The @api.errorhandler decorator

The @api.errorhandler decorator allows you to register a specific handler for a given exception (or any exceptions inherited from it), in the same manner that you can do with Flask/Blueprint @errorhandler decorator.

@api.errorhandler(RootException)
def handle_root_exception(error):
    '''Return a custom message and 400 status code'''
    return {'message': 'What you want'}, 400


@api.errorhandler(CustomException)
def handle_custom_exception(error):
    '''Return a custom message and 400 status code'''
    return {'message': 'What you want'}, 400


@api.errorhandler(AnotherException)
def handle_another_exception(error):
    '''Return a custom message and 500 status code'''
    return {'message': error.specific}


@api.errorhandler(FakeException)
def handle_fake_exception_with_header(error):
    '''Return a custom message and 400 status code'''
    return {'message': error.message}, 400, {'My-Header': 'Value'}


@api.errorhandler(NoResultFound)
def handle_no_result_exception(error):
    '''Return a custom not found error message and 404 status code'''
    return {'message': error.specific}, 404

Note

A “NoResultFound” error with description is required by the OpenAPI 2.0 spec. The docstring in the error handle function is output in the swagger.json as the description.

You can also document the error:

@api.errorhandler(FakeException)
@api.marshal_with(error_fields, code=400)
@api.header('My-Header',  'Some description')
def handle_fake_exception_with_header(error):
    '''This is a custom error'''
    return {'message': error.message}, 400, {'My-Header': 'Value'}


@api.route('/test/')
class TestResource(Resource):
    def get(self):
        '''
        Do something

        :raises CustomException: In case of something
        '''
        pass

In this example, the :raise: docstring will be automatically extracted and the response 400 will be documented properly.

It also allows for overriding the default error handler when used without parameter:

@api.errorhandler
def default_error_handler(error):
    '''Default error handler'''
    return {'message': str(error)}, getattr(error, 'code', 500)

Note

Flask-RESTX will return a message in the error response by default. If a custom response is required as an error and the message field is not needed, it can be disabled by setting ERROR_INCLUDE_MESSAGE to False in your application config.

Error handlers can also be registered on namespaces. An error handler registered on a namespace will override one registered on the api.

ns = Namespace('cats', description='Cats related operations')

@ns.errorhandler
def specific_namespace_error_handler(error):
    '''Namespace error handler'''
    return {'message': str(error)}, getattr(error, 'code', 500)