Insights

Setting Up Middleware in FastAPI

Setting Up Middleware in FastAPI

Setting Up Middleware in FastAPI

Saurabh Jain

Aug 31, 2024

FastAPI is an increasingly popular framework for building APIs in Python due to its speed, simplicity, and powerful features. One of its key features is the ability to easily add middleware, which allows you to process requests and responses globally across your application. Middleware can be used for tasks such as logging, authentication, CORS handling, and more. In this article, we’ll explore how to set up middleware in FastAPI and provide examples to demonstrate how it works.

What is Middleware?

Middleware in FastAPI refers to a piece of code that runs before and after each request. It allows you to modify requests, responses, or perform specific actions (like logging or authentication) without altering the core business logic of your API. Middleware is executed in a defined order, so you can chain multiple middleware functions to handle different tasks.

Basic Middleware Setup in FastAPI

To set up middleware in FastAPI, you can use the add_middleware() method, which is available on the FastAPI app instance. The following is a basic example of middleware that logs the time taken to process each request.

from fastapi import FastAPI, Request
import time
app = FastAPI()

# This middleware is installed for all handlers
@app.middleware("http")
async def log_request_time(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    print(f"Request: {request.url} took {process_time} seconds")
    return response

@app.get("/")
async def read_root():
    return {"message": "Hello World!"}

In this example, the log_request_time middleware logs the time it takes to process each request. The `call_next` function is used to pass the request to the next middleware in the stack or the route handler.

Adding Middleware Using Third-Party Libraries

FastAPI supports the integration of third-party middleware, such as the CORS middleware provided by starlette.middleware. CORS (Cross-Origin Resource Sharing) is a security feature that restricts resources on a web page to be requested from another domain. Below is an example of adding CORS middleware to your FastAPI app.

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
app = FastAPI()
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # Allow all origins
    allow_credentials=True,
    allow_methods=["*"],  # Allow all methods (GET, POST, etc.)
    allow_headers=["*"],  # Allow all headers
)

@app.get("/")
async def read_root():
    return {"message": "Hello, CORS is enabled!"}

In this example, we use the add_middleware() method to add CORSMiddleware to the FastAPI application. The middleware configuration allows all origins, methods, and headers, making it suitable for development. In production, you should restrict these settings to specific domains, methods, and headers.

Custom Authentication Middleware

One common use case for middleware is to implement custom authentication logic. Below is an example of middleware that checks for an API key in the request headers.

from fastapi import FastAPI, Request, HTTPException
app = FastAPI()

@app.middleware("http")
async def api_key_authentication(request: Request, call_next):
    api_key = request.headers.get("X-API-Key")
    if api_key != "your-secret-api-key":
        raise HTTPException(status_code=401, detail="Invalid API Key")
    
    response = await call_next(request)
    return response

@app.get("/protected")
async def protected_route():
    return {"message": "You are authorized!"}

In this example, the middleware checks for the presence of a specific API key in the X-API-Key header. If the key is missing or incorrect, the middleware raises an HTTPException with a 401 status code. Otherwise, the request is passed to the next handler.

Ordering of Middleware

In FastAPI, middleware is executed in the order it is added. This means that if you add multiple middleware components, they will be executed sequentially. It’s important to consider the order in which you add middleware, as it can affect the behavior of your application.

For example, you might want to ensure that logging middleware runs first so that it captures all incoming requests, even those that are rejected by subsequent authentication middleware.

app.add_middleware(FirstMiddleware)
app.add_middleware(SecondMiddleware)

In the above example, `FirstMiddleware` will execute before `SecondMiddleware` on incoming requests, and `SecondMiddleware` will execute before `FirstMiddleware` on the way back out.

Example: Combining Multiple Middleware

Let’s combine several middleware components in a single FastAPI application. We’ll use CORS middleware, logging middleware, and custom authentication middleware together.

from fastapi import FastAPI, Request, HTTPException
from fastapi.middleware.cors import CORSMiddleware
import time

app = FastAPI()
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  
    allow_credentials=True,
    allow_methods=["*"],  
    allow_headers=["*"],  
)

@app.middleware("http")
async def log_request_time(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    print(f"Request: {request.url} took {process_time} seconds")
    return response

@app.middleware("http")
async def api_key_authentication(request: Request, call_next):
    api_key = request.headers.get("X-API-Key")
    if api_key != "your-secret-api-key":
        raise HTTPException(status_code=401, detail="Invalid API Key")
    response = await call_next(request)
    return response

@app.get("/protected")
async def protected_route():
    return {"message": "You are authorized!"}

In this example, CORS middleware is applied first, followed by logging middleware and then authentication middleware. This ensures that all requests are logged and authenticated after passing the CORS checks.

Conclusion

Middleware in FastAPI provides a powerful mechanism for handling cross-cutting concerns like logging, security, and performance optimizations. By using both built-in and third-party middleware, you can easily scale and secure your applications. The flexibility of FastAPI allows you to customize middleware to suit your application’s specific needs while maintaining clean and maintainable code. Whether you’re implementing simple logging or complex authentication, FastAPI’s middleware system makes it easy to manage global request processing logic.

Saurabh Jain

Share this post