In FastAPI, middleware is a very useful feature that allows us to uniformly handle logic such as authentication, logging, and error handling before a request reaches the view function and after the response is returned to the client. This article will walk you through a practical case to implement a simple middleware for recording request logs and statistics on response times, making your API development more standardized and easier to debug.
1. Environment Preparation¶
First, ensure you have FastAPI and Uvicorn (the server for running FastAPI applications) installed. If not, install them using the following command:
pip install fastapi uvicorn
2. Role of Middleware¶
Why use middleware for request logging and response time statistics? Imagine if you manually recorded this information in each view function—this would result in a lot of repeated code, and changes (e.g., adding new fields) would be cumbersome. Middleware helps you centralize this logic, ensuring all requests automatically pass through the middleware, which is both concise and easy to maintain.
3. Implementing Middleware for Request Logging and Response Time Statistics¶
We need to create a middleware class that inherits from BaseHTTPMiddleware provided by Starlette (since FastAPI is built on Starlette, middleware logic is managed by Starlette) and implement the logic for logging and time statistics in the dispatch method.
1. Define the Middleware Class¶
from fastapi import FastAPI
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
import time
class LoggingMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
# Record the start timestamp of the request
start_time = time.time()
# Call the next middleware or view function to get the response
response = await call_next(request)
# Calculate response time (end time - start time)
duration = time.time() - start_time
# Construct log information
log_info = (
f"[Request Log] Method: {request.method} | "
f"Path: {request.url.path} | "
f"Client IP: {request.client.host} | "
f"Duration: {duration:.4f}s | "
f"Status Code: {response.status_code}"
)
# Print log (replace with logging module to output to file in production)
print(log_info)
return response
2. Explain Middleware Logic¶
- Inherit
BaseHTTPMiddleware: This is the base class for middleware provided by Starlette, encapsulating the basic processing flow. You only need to implement thedispatchmethod. dispatchMethod: The core method of the middleware, which takes two parameters:request: The current request object (contains method, path, client info, etc.).call_next: An async function to call the next middleware or view function and return the processed response.- Time Statistics: Record the start time before processing the request, then the end time after processing, and calculate the duration.
- Log Construction: Combine request method, path, client IP, duration, and response status code into a single log for easy debugging.
4. Add Middleware to the FastAPI Application¶
After creating the FastAPI app, add the middleware using the add_middleware method:
# Create a FastAPI app instance
app = FastAPI()
# Add the middleware (applies globally)
app.add_middleware(LoggingMiddleware)
5. Test the Middleware Effect¶
Define a few simple route functions to test if the middleware correctly records logs and response times.
1. Define Test Routes¶
@app.get("/")
async def root():
return {"message": "Hello, FastAPI!"}
@app.get("/items/{item_id}")
async def read_item(item_id: int):
return {"item_id": item_id, "item_name": f"Item {item_id}"}
@app.post("/users")
async def create_user(name: str):
return {"user": {"name": name, "status": "created"}}
2. Run and Test the Application¶
Start the app using Uvicorn:
uvicorn main:app --reload
Then visit different endpoints (e.g., http://localhost:8000/, http://localhost:8000/items/123, http://localhost:8000/users?name=test) and check the console for log output.
3. Example Log Output¶
After accessing http://localhost:8000/, you might see output like:
[Request Log] Method: GET | Path: / | Client IP: 127.0.0.1 | Duration: 0.0002s | Status Code: 200
6. Extensions and Optimizations¶
The basic implementation above can be extended based on your needs:
- Use the
loggingModule: Replaceprintwith Python’sloggingmodule to output logs to files with different levels (INFO/WARNING/ERROR). - Log Request Body: For POST/PUT requests, use
await request.json()to capture request data (remember to sanitize sensitive information). - Error Handling: Add exception catching in the middleware to log error stacks.
- CORS Support: Include the CORS middleware if cross-origin resource sharing is needed.
7. Conclusion¶
Through this article, you’ve learned to use FastAPI middleware to centrally handle request logging and response time statistics, avoiding repetitive code and improving maintainability. Middleware is a powerful tool for managing request/response logic in FastAPI (and Starlette). You can further encapsulate common logic (e.g., authentication, CORS) into middleware to make API development more efficient and standardized.