Search code examples
pythonflaskpython-decorators

Changing order of Flask and custom decorators breaks custom decorators


I made a logging decorator for all HTTP calls:

def log_http_call(flask_request_getter: typing.Callable[[], flask.Request]):
    def arg_wrapper(wrapped_function):
        @wraps(wrapped_function)
        def wrapper(*args, **kwargs):
            flask_request: flask.Request = flask_request_getter()
            print(f'HTTP Method {flask_request.method}: {flask_request.path}')
            return wrapped_function(*args, **kwargs)    
        return wrapper    
    return arg_wrapper


@app.route('/api/all', methods=['GET'])
@log_http_call(lambda: flask.request)
def get_all():
    return "Here you go"


@app.route('/api/<int:_id>/<string:name>', methods=['GET'])
@log_http_call(lambda: flask.request)
def get_one(_id, name):
    return f"{name}'s ID is {_id}"

It's working this way, but if I reverse the order of the decorators to e.g.:

@log_http_call(lambda: flask.request)
@app.route('/api/all', methods=['GET'])
def get_all():
    return "Here you go"

It's no longer working.

Since other consumers of my code may place these decorators in different order, I want to make sure that they work either way.

How can I make it work in any order?


Solution

  • The Flask docs specifically state the route decorator must be the outermost. There is no way around this except modifying the Flask library yourself (which seems like a daunting task given that the developers probably would have supported this already if it was easy).

    Much like Flask put that comment in their documentation, you can put a similar comment in your documentation (or just reference the Flask docs).