Middleware in Django and FastAPI Web Pipelines

Middleware functions as an intermediary layer in modern web frameworks, intercepting HTTP requests before they reach route handlers and modifying HTTP responses before they return to the client. In Python web development, both Django and FastAPI rely on middleware to handle cross-cutting concerns such as authentication, Cross-Origin Resource Sharing (CORS), session management, request logging, and error handling. While both frameworks use middleware to create modular, reusable processing pipelines, their underlying architectures—Django's synchronous-first WSGI/ASGI heritage versus FastAPI's native asynchronous ASGI design—dictate how these components are constructed and executed.

The Core Concept of Middleware

In a web application pipeline, incoming requests and outgoing responses traverse a series of layers arranged in an "onion" architecture. When a client sends a request, it enters the outer layer of the middleware stack, passes sequentially through each middleware component, reaches the core view or route handler, and then travels back out through the same middleware components in reverse order. This allows developers to inspect, modify, short-circuit, or augment request and response data globally without altering individual endpoint logic.

Middleware in Django

Django's middleware system is historically built on the Web Server Gateway Interface (WSGI) standard, though modern versions support the Asynchronous Server Gateway Interface (ASGI) as well. In Django, a middleware component is typically implemented as a Python class with a __call__ method, taking get_response as a callable during initialization.

class SimpleLoggingMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # Code executed before the view is called
        response = self.get_response(request)
        # Code executed after the view is called
        return response

Key Functions in Django:

Middleware in FastAPI

FastAPI is built on top of Starlette and utilizes ASGI natively. Because FastAPI operates asynchronously from the ground up, its middleware components are async functions designed to handle high-concurrency workloads using Python's asyncio ecosystem.

FastAPI middleware intercepts requests using the @app.middleware("http") decorator or by subclassing Starlette's BaseHTTPMiddleware.

import time
from fastapi import FastAPI, Request

app = FastAPI()

@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    start_time = time.perf_counter()
    response = await call_next(request)
    process_time = time.perf_counter() - start_time
    response.headers["X-Process-Time"] = str(process_time)
    return response

Key Functions in FastAPI:

Comparing Django and FastAPI Pipelines

Feature Django Middleware FastAPI Middleware
Primary Standard WSGI (with optional ASGI support) Native ASGI
Execution Paradigm Synchronous by default Asynchronous (async/await)
Lifecycle Hooks Multiple (process_view, process_exception) Unified dispatch / call_next pattern
Integration Configured in settings.py via string paths Added directly to the application instance

In both frameworks, the execution order is determined by the order of definition. Requests pass through the list from top to bottom, while responses return from bottom to top. Understanding this directional flow is essential for ensuring that dependencies, such as authentication contexts or correlation IDs, are established before downstream components attempt to access them.