Middleware lets you run code before or after each request in your app. Custom middleware helps you add your own steps to handle requests or responses.
Custom middleware creation in FastAPI
Start learning this pattern below
Jump into concepts and practice - no test required
or
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Introduction
Syntax
FastAPI
from fastapi import FastAPI, Request from starlette.middleware.base import BaseHTTPMiddleware class CustomMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): # Code before request response = await call_next(request) # Code after response return response app = FastAPI() app.add_middleware(CustomMiddleware)
The dispatch method runs for each request.
Use call_next(request) to continue processing the request.
Examples
FastAPI
class LogMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): print(f"Request path: {request.url.path}") response = await call_next(request) print(f"Response status: {response.status_code}") return response
FastAPI
import time class TimerMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): start = time.time() response = await call_next(request) duration = time.time() - start response.headers["X-Process-Time"] = str(duration) return response
Sample Program
This FastAPI app uses custom middleware to measure how long each request takes. The time is added as a header in the response.
FastAPI
from fastapi import FastAPI, Request from starlette.middleware.base import BaseHTTPMiddleware import time class TimerMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): start = time.time() response = await call_next(request) duration = time.time() - start response.headers["X-Process-Time"] = str(duration) return response app = FastAPI() app.add_middleware(TimerMiddleware) @app.get("/") async def root(): return {"message": "Hello, world!"}
Important Notes
Middleware runs for every request, so keep code efficient.
Always call call_next(request) to continue processing.
You can modify request or response inside middleware as needed.
Summary
Custom middleware lets you add code before and after requests.
Use dispatch method and call_next to handle requests.
Middleware is useful for logging, timing, security, and modifying requests or responses.
Practice
1. What is the main purpose of creating custom middleware in FastAPI?
easy
Solution
Step 1: Understand middleware role
Middleware runs code around request processing, before and after the main handler.Step 2: Identify correct purpose
Custom middleware is not for database or templates but for request/response handling.Final Answer:
To run code before and after each request is processed -> Option DQuick Check:
Middleware = pre/post request code [OK]
Hint: Middleware wraps requests to add extra processing [OK]
Common Mistakes:
- Confusing middleware with database or template code
- Thinking middleware only handles authentication
- Believing middleware runs only after requests
2. Which method must be overridden when creating a custom middleware class in FastAPI?
easy
Solution
Step 1: Recall FastAPI middleware structure
Custom middleware classes override the dispatch method to handle requests.Step 2: Match method names
Only dispatch is the correct method name; others are invalid in FastAPI middleware.Final Answer:
dispatch -> Option AQuick Check:
dispatch method overrides middleware behavior [OK]
Hint: dispatch handles request and response in middleware [OK]
Common Mistakes:
- Using incorrect method names like handle_request
- Confusing middleware methods with route handlers
- Forgetting to override dispatch method
3. Given this middleware code snippet, what will be printed when a request is processed?
class LogMiddleware:
async def dispatch(self, request, call_next):
print('Before request')
response = await call_next(request)
print('After request')
return responsemedium
Solution
Step 1: Analyze dispatch method flow
Print 'Before request' runs before calling next handler, 'After request' runs after awaiting response.Step 2: Understand async call_next behavior
call_next processes the request and returns response; code after await runs after response is ready.Final Answer:
Before request printed, then After request printed after response -> Option BQuick Check:
Print before and after call_next = B [OK]
Hint: Code before await runs first, after await runs last [OK]
Common Mistakes:
- Thinking 'After request' prints before response
- Ignoring async await order
- Assuming only one print runs
4. Identify the error in this custom middleware code:
class MyMiddleware:
async def dispatch(self, request):
response = await call_next(request)
return responsemedium
Solution
Step 1: Check dispatch method signature
dispatch must accept both request and call_next parameters to call next handler.Step 2: Identify missing parameter
Code lacks call_next parameter, causing runtime error when calling call_next(request).Final Answer:
Missing call_next parameter in dispatch method -> Option CQuick Check:
dispatch(request, call_next) required [OK]
Hint: dispatch needs call_next argument to forward requests [OK]
Common Mistakes:
- Omitting call_next parameter
- Making dispatch synchronous
- Not inheriting middleware base class (optional but recommended)
5. You want to create a middleware that adds a custom header 'X-Process-Time' showing how long the request took. Which code snippet correctly implements this?
hard
Solution
Step 1: Check dispatch method signature and async usage
dispatch must be async and accept request and call_next parameters.Step 2: Verify timing and header addition
Start time before await call_next, calculate duration after, add header as string.Step 3: Identify correct code snippet
class TimerMiddleware: async def dispatch(self, request, call_next): start = time.time() response = await call_next(request) process_time = time.time() - start response.headers['X-Process-Time'] = str(process_time) return response correctly implements timing, async, and header addition.Final Answer:
The code snippet that correctly adds X-Process-Time header -> Option AQuick Check:
Async dispatch with timing and header = A [OK]
Hint: Measure time before and after await call_next, add header [OK]
Common Mistakes:
- Missing call_next parameter
- Not awaiting call_next
- Adding header before timing calculation
- Using synchronous dispatch method
