Implementing Before and After Request Hooks

Tutorial 2 of 5

Implementing Before and After Request Hooks

1. Introduction

In this tutorial, we'll learn how to implement before and after request hooks using Flask, a popular web framework for Python. Flask enables you to execute code at specific points in the request/response cycle, which is particularly useful for tasks such as authentication, logging, or modifying responses.

By the end of this tutorial, you should be able to:
- Understand the concept of request hooks in Flask
- Implement before and after request hooks in your web applications

Prerequisites

This tutorial assumes you have basic knowledge of Python and a fundamental understanding of Flask. If you're new to Flask, I recommend reading Flask's official documentation before proceeding with this tutorial.

2. Step-by-Step Guide

Request hooks in Flask are decorators that allow you to trigger certain functions before or after a request has been processed.

The @app.before_request decorator triggers the function before each request, while the @app.after_request decorator triggers the function after each request, but before the response has been sent to the client.

These hooks can be very useful in many scenarios. For instance, @app.before_request can be used to check if a user is authenticated before allowing them to access a route. @app.after_request can be used to modify responses, for example, adding custom headers.

3. Code Examples

Let's see these hooks in action.

Example 1: Using @app.before_request

from flask import Flask, abort

app = Flask(__name__)

@app.before_request
def check_user():
    # Here we pretend to check user authentication
    # In a real application, you would check the user session or a token
    user_authenticated = False 
    if not user_authenticated:
        abort(401)  # abort with HTTP 401 Unauthorized if user is not authenticated

@app.route('/')
def index():
    return "Welcome to the home page!"

if __name__ == "__main__":
    app.run(debug=True)

In this example, the check_user function runs before any request. If the user is not authenticated, it aborts the request with a 401 Unauthorized status code.

Example 2: Using @app.after_request

from flask import Flask, jsonify

app = Flask(__name__)

@app.after_request
def apply_caching(response):
    response.headers["X-Custom-Header"] = "This is a custom header"
    return response

@app.route('/')
def index():
    return jsonify(message="Welcome to the home page!")

if __name__ == "__main__":
    app.run(debug=True)

In this example, the apply_caching function runs after each request, but before the response has been sent to the client. It adds a custom X-Custom-Header to the response.

4. Summary

We've covered how to use Flask's before and after request hooks to execute code at specific points in the request/response cycle. You've learned how to use @app.before_request to run code before each request and how to use @app.after_request to modify responses before they're sent to the client.

Continue learning about Flask by exploring other decorators such as @app.teardown_request and @app.context_processor.

5. Practice Exercises

Exercise 1: Create a Flask application that checks if a custom "X-Api-Key" header is present in the request before processing it. If it's not present, return a 403 Forbidden status.

Exercise 2: Adjust the above application to add a custom "X-Response-Time" header to each response, indicating how long it took to process the request.

Solutions:

  1. Check for "X-Api-Key" header
@app.before_request
def check_api_key():
    if 'X-Api-Key' not in request.headers:
        abort(403)
  1. Add "X-Response-Time" header
import time

@app.before_request
def start_timer():
    g.start = time.time()

@app.after_request
def calculate_time(response):
    diff = time.time() - g.start
    response.headers["X-Response-Time"] = str(diff)
    return response

In the first solution, we use request.headers to access the headers and abort the request if "X-Api-Key" is not present. In the second solution, we use Flask's g object to store the start time of the request and then calculate the difference in the calculate_time function.