Flask Request Middleware with CORS, Logging, and API Key Authentication

mediumPython

Lesson

Flask Middleware with before_request and after_request

Flask middleware allows you to execute code before and after every request, making it perfect for cross-cutting concerns like authentication, logging, and CORS headers. Flask provides two key decorators for this: @app.before_request and @app.after_request.

How Flask Request Hooks Work

The @app.before_request decorator registers a function that runs before any route handler is called. This is ideal for:

  • Authentication and authorization checks
  • Request validation
  • Setting up request-scoped data
  • Starting timers for performance monitoring

The @app.after_request decorator registers a function that runs after the route handler completes, receiving the response object as a parameter. This is perfect for:

  • Adding response headers (like CORS)
  • Logging request completion
  • Modifying response data
  • Cleanup tasks

Using Flask's g Object

Flask provides the g object (application context global) to store data that needs to be shared between before_request and after_request handlers within the same request. Unlike session data, g is request-scoped and automatically cleaned up after each request.

Error Handling in Middleware

If a before_request function returns a response (like jsonify() with a status code), Flask skips the route handler and jumps directly to the after_request handlers. This makes it perfect for authentication middleware that can reject requests early.

Middleware runs in the order it's defined, so organize your handlers logically. Authentication should typically run before other processing, while response modification (like adding headers) should happen in after_request handlers.

Example
1from flask import Flask, g, request, jsonify 2import time 3 4app = Flask(__name__) 5 6@app.before_request 7def start_timer(): 8 g.start_time = time.time() 9 print(f"Starting request to {request.path}") 10 11@app.after_request 12def add_headers_and_log(response): 13 # Add a custom header to all responses 14 response.headers['X-Processing-Time'] = f"{time.time() - g.start_time:.3f}s" 15 print(f"Completed {request.method} {request.path}") 16 return response 17 18@app.route('/hello') 19def hello(): 20 return jsonify({"message": "Hello, World!"})
L7g.start_time stores data that persists for this request only
L12after_request functions must return the response object
L13Access the stored start time to calculate duration

Key Takeaways

  • •before_request handlers can return early responses to skip route processing, perfect for authentication
  • •Use Flask's g object to share data between before_request and after_request within the same request
  • •after_request handlers always run and must return the response object, making them ideal for adding headers
Loading...