flaskflask-restful

What is the convention in Flask-RESTful for error handling


I'm struggling with the conventional error handling in flask API using Flask-RESTful..

So basically I have an endpoint in my main.py:

error_handler(app)

class MyEndpoint(Resource):
    def post(self):
        try:
            result = my_function()
            return result
        except Exception as e:
            abort(400, message=f"{e.args[0]}")

I also have a my_function defined in my be.py file:

def my_function():
    try:
        #some logic
    except Exception as e:
        #logger
        raise

where I'm logging and raising the exception again..

I also have a error handler in my errors.py, to handle the aborted function:

def error_handler(app):
    @app.errorhandler(400)
    def bad_request_error(error):
        description = getattr(error, 'description', 'Bad request')
        return jsonify({'error': 'Bad request', 'message': description}), 400

Is this the conventional way to do it? Is it more optimal to abort the function right into the except block in my_function() ?


Solution

  • A good design separates error handling logic from your business logic. You can achieve this through use of custom exceptions defined for your business domain and shift the error handling logic to Flask's global or local error handler at the blueprint level.

    class MyEndpoint(Resource):
        def post(self):
           return my_function()
    

    my_function can be refactored to raise a custom error e.g. BusinessLogicException.

    class BusinessLogicException(Exception):
        def __init__(message):
            super().__init__(message)
    
    
    def my_function():
        # ... 
        raise BusinessLogicException('Could not perform some business operation.')
    

    You can register an error handler for the exception raised when performing the domain logic and return the appropriate response.

    You can see a similar design pattern used in the Apache Superset project.

    def error_handler(app):
        @app.errorhandler(BusinessLogicException)
        def my_function_exception(ex):
            description = getattr(ex, 'message', 'Bad request')
            return jsonify({'error': 'Bad request', 'message': description}), 400