How to Add Middleware in FastAPI Applications

FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints. Middleware plays a crucial role in web applications as it allows you to process requests before they reach the route handlers and responses before they are sent back to the client. In this blog, we will explore how to add middleware in FastAPI applications, covering fundamental concepts, usage methods, common practices, and best practices.

Table of Contents

  1. What is Middleware?
  2. Adding Middleware in FastAPI
  3. Common Practices of Middleware in FastAPI
  4. Best Practices for Using Middleware in FastAPI
  5. Conclusion
  6. References

What is Middleware?

Middleware is a piece of code that sits between the web server and the route handlers in a web application. It intercepts incoming requests and outgoing responses, allowing you to perform various tasks such as logging, authentication, request/response modification, and more. Middleware can be used to add cross - cutting concerns to your application without cluttering the route handlers.

Adding Middleware in FastAPI

Built - in Middleware

FastAPI comes with some built - in middleware that you can easily add to your application. For example, the CORSMiddleware is used to handle Cross - Origin Resource Sharing (CORS).

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# List of allowed origins
origins = [
    "http://localhost",
    "http://localhost:8080",
]

# Add CORS middleware
app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


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

In this example, we first import the CORSMiddleware from fastapi.middleware.cors. Then we define a list of allowed origins and add the middleware to our FastAPI application using the add_middleware method.

Custom Middleware

You can also create your own custom middleware. A custom middleware in FastAPI is an asynchronous function that takes a request object and a call_next function. The call_next function is used to pass the request to the next middleware or the route handler.

from fastapi import FastAPI, Request
import time

app = FastAPI()


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


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

In this example, we define a custom middleware using the @app.middleware("http") decorator. The middleware measures the time it takes to process a request and adds a custom header X - Process - Time to the response.

Common Practices of Middleware in FastAPI

Logging

You can use middleware to log incoming requests and outgoing responses. This can be useful for debugging and monitoring purposes.

from fastapi import FastAPI, Request
import logging

app = FastAPI()

logging.basicConfig(level=logging.INFO)


@app.middleware("http")
async def log_requests(request: Request, call_next):
    logging.info(f"Request: {request.method} {request.url}")
    response = await call_next(request)
    logging.info(f"Response status code: {response.status_code}")
    return response


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

Authentication

Middleware can be used to perform authentication checks on incoming requests. For example, you can check for the presence of an authentication token in the request headers.

from fastapi import FastAPI, Request, HTTPException

app = FastAPI()


@app.middleware("http")
async def authenticate(request: Request, call_next):
    token = request.headers.get("Authorization")
    if not token:
        raise HTTPException(status_code=401, detail="Unauthorized")
    # Here you can add more complex authentication logic
    response = await call_next(request)
    return response


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

Best Practices for Using Middleware in FastAPI

Keep Middleware Simple

Each middleware should have a single responsibility. For example, a logging middleware should only focus on logging, and an authentication middleware should only focus on authentication. This makes the code more maintainable and easier to understand.

Order of Middleware Matters

The order in which you add middleware to your FastAPI application matters. Middleware is executed in the order they are added. So, if you have an authentication middleware and a logging middleware, you may want to add the authentication middleware first to prevent unnecessary logging of unauthorized requests.

from fastapi import FastAPI, Request, HTTPException
import logging

app = FastAPI()

logging.basicConfig(level=logging.INFO)


@app.middleware("http")
async def authenticate(request: Request, call_next):
    token = request.headers.get("Authorization")
    if not token:
        raise HTTPException(status_code=401, detail="Unauthorized")
    response = await call_next(request)
    return response


@app.middleware("http")
async def log_requests(request: Request, call_next):
    logging.info(f"Request: {request.method} {request.url}")
    response = await call_next(request)
    logging.info(f"Response status code: {response.status_code}")
    return response


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

Error Handling

Make sure to handle errors properly in your middleware. If an error occurs in a middleware, it should either return an appropriate error response or raise an exception that can be handled by the global exception handler in FastAPI.

Conclusion

Middleware is a powerful feature in FastAPI that allows you to add cross - cutting concerns to your application in a modular and efficient way. By understanding how to add built - in and custom middleware, and following common and best practices, you can build more robust and maintainable FastAPI applications. Whether it’s handling CORS, logging, or authentication, middleware provides a flexible way to enhance your application’s functionality.

References