Reputation: 320
I have a simple Flask app where i want to validate requests in json format with a decorator like this:
def validate_request(*expected_args):
"""
Validate requests decorator
"""
# print('=======================ENTER VALIDATE_REQUEST================')
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
json_obj = request.get_json()
for expected_arg in expected_args:
if expected_arg not in json_obj or json_obj.get(expected_arg) is None:
return api_response({'error': f"You must call with all request params: {', '.join(expected_args)}"})
return func(*args, **kwargs)
return wrapper
return decorator
And on the route side like this:
@user_api.route('/login', methods=['POST'])
@validate_request('email', 'password')
def login():
req_data = request.get_json()
......................
My question is why the PRINT statement from decorator is not shown when i call '/login' route?
The message is logged only when i start the server(flask run).
Thank you.
Upvotes: 1
Views: 437
Reputation: 1209
Your print statement is in validate_request
. Although validate_request
returns a decorator, it is not a decorator itself. It is a decorator factory if you will, and is only executed once to create the decorator and decorate login
when python loads your code, hence why your print statement only gets executed once when you boot up your server. Keep in mind that the decorator itself is also executed just once to replace login
with whatever the decorator returns, in this case, wrapper
. So, wrapper
is the actual function that will be called on each request. If you put your print statement there, you'll see it on each request.
def validate_request(*expected_args):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("=== Enter validate request ===")
return func(*args, **kwargs)
return wrapper
return decorator
Upvotes: 1
Reputation: 92440
Python decorators replace the functions they are decorating. This replacement happens at the start of the program when the interpreter reads the code. This is when your print statement will be executed. After this time, the returned function is the only code that will run. If you want the print to run at every call, you need to put in the actual function that will be called:
def validate_request(*expected_args):
"""
Validate requests decorator
"""
# print('=======================Function Decoration Happening================')
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("==== ENTER VALIDATE_REQUEST ===")
json_obj = request.get_json()
for expected_arg in expected_args:
if expected_arg not in json_obj or json_obj.get(expected_arg) is None:
return api_response({'error': f"You must call with all request params: {', '.join(expected_args)}"})
return func(*args, **kwargs)
return wrapper
return decorator
Upvotes: 1