Top 10 FastAPI Middleware Solutions for Optimizing Your Application

Jennie Lee
12 min readMar 15, 2024

--

Looking for a Postman alternative?

Try APIDog, the Most Customizable Postman Alternative, where you can connect to thousands of APIs right now!

Introduction to FastAPI Middleware

Overview of FastAPI and its benefits

FastAPI is a modern, fast (high-performance), web framework for building APIs with Python 3.7+ based on standard Python type hints. It is built on top of Starlette for web routing, Pydantic for data validation and serialization, and other libraries for high-performance async requests handling.

One of the key benefits of FastAPI is its incredible speed. It is one of the fastest web frameworks available for Python, outperforming popular frameworks like Flask and Django. It achieves this speed through the use of asynchronous code and type annotations, which bring performance optimizations and automatic data validation and serialization.

In addition to its speed, FastAPI provides auto-generation of documentation with OpenAPI and JSON Schema support, interactive API documentation (via Swagger UI and Redoc), and automatic validation based on function parameters. FastAPI also supports background tasks, websockets, dependency injection, and more.

Introduction to middleware and its role in FastAPI applications

Middleware in FastAPI is a powerful tool that allows you to modify the behavior of your application by intercepting and processing incoming HTTP requests and outgoing HTTP responses. Middleware functions sit in the middle of the request-response lifecycle, allowing you to perform operations before and after the request is handled by your API endpoints.

By creating custom middleware, you can extend the functionality of FastAPI and add additional features or logic to your application. This includes authentication, request filtering, request modification, response modification, error handling, and much more. Middleware functions can be added to your FastAPI application in a modular way, making it easy to reuse and configure them as needed.

Importance of custom middleware for extending FastAPI functionality

While FastAPI provides a wide range of features and capabilities out of the box, there may be specific requirements or functionalities that are not provided by default. In such cases, custom middleware can be used to add these functionalities seamlessly to your FastAPI application.

Custom middleware allows you to tailor the behavior of your application to suit your specific needs. It provides a flexible and modular way to incorporate additional functionalities without cluttering the business logic of your API endpoints.

In this article, we will explore the top 10 FastAPI middleware solutions that can be used to optimize your application and enhance its capabilities. These middleware solutions cover various aspects such as token authentication, content-type handling, serving UI files, and more.

Token Authentication in FastAPI Middleware

Understanding token authentication and its role in securing API endpoints

Token authentication is a widely used technique for securing API endpoints. It involves generating a token (usually a JSON Web Token or JWT) on the server-side and sending it to the client. The client then includes this token in subsequent requests to authenticate itself.

Token authentication is stateless, meaning that the server does not need to store any session data and can authenticate each request independently. This makes it scalable and ideal for building RESTful APIs where clients interact with various endpoints.

In FastAPI, token authentication can be implemented using middleware. The middleware intercepts incoming requests, checks the presence and validity of the token, and allows or denies access to the API endpoints based on the authentication status.

Integration with Azure AD JWKS endpoint for token validation

To implement token authentication in FastAPI, we can integrate with the Azure Active Directory (AD) JSON Web Key Set (JWKS) endpoint. Azure AD is a cloud-based identity and access management service provided by Microsoft.

The JWKS endpoint of Azure AD provides a set of cryptographic keys that can be used to verify the authenticity and integrity of JSON Web Tokens issued by Azure AD. By validating the token against the Azure AD JWKS endpoint, we can ensure that the user is authenticated and authorized to access the API endpoints.

Implementation of token authentication in the custom middleware

To implement token authentication in FastAPI using custom middleware, we can create a middleware function that intercepts incoming requests, extracts the token from the Authorization header, and validates it against the Azure AD JWKS endpoint.

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from pydantic import BaseModel

# Load environment variables
import os
from dotenv import load_dotenv

load_dotenv()

class Token(BaseModel):
access_token: str

def validate_token(token: str) -> bool:
# Implement token validation using Azure AD JWKS endpoint
# ...
return True

async def token_authentication(request: Request, call_next):
token = request.headers.get("Authorization").split("Bearer ")[1]
if validate_token(token):
return await call_next(request)
else:
return JSONResponse(status_code=401, content={"error": "Unauthorized"})

app = FastAPI()

app.middleware("http")(token_authentication)

In the code snippet above, we define a Token model using Pydantic to validate the request payload. We then implement the validate_token function, which is responsible for validating the token against the Azure AD JWKS endpoint. This function should be implemented based on the specific requirements of your application.

The token_authentication function is a middleware function that intercepts incoming requests and extracts the token from the Authorization header. It then calls the validate_token function to verify the validity of the token. If the token is valid, it passes the request to the next middleware or the API endpoint itself. Otherwise, it returns a 401 Unauthorized JSON response.

Finally, we add the middleware function to the FastAPI application using the app.middleware function.

Step-by-step guide for configuring and utilizing token authentication in FastAPI

To configure and utilize token authentication in FastAPI with the custom middleware, follow these steps:

  1. Install the required dependencies. You can use pip to install FastAPI and other dependencies:
  • pip install fastapi pydantic python-dotenv
  1. Import the required modules and classes:
  • from fastapi import FastAPI, Request from fastapi.responses import JSONResponse from pydantic import BaseModel import os from dotenv import load_dotenv
  1. Load the environment variables using dotenv:
  • load_dotenv()
  1. Define the Token model using Pydantic:
  • class Token(BaseModel): access_token: str
  1. Implement the validate_token function to validate the token against the Azure AD JWKS endpoint. This function should return True if the token is valid and False otherwise.
  • def validate_token(token: str) -> bool: # Implement token validation using Azure AD JWKS endpoint # ... return True
  1. Define the token_authentication function as the middleware function:
  • async def token_authentication(request: Request, call_next): token = request.headers.get("Authorization").split("Bearer ")[1] if validate_token(token): return await call_next(request) else: return JSONResponse(status_code=401, content={"error": "Unauthorized"})
  1. Create an instance of the FastAPI class:
  • app = FastAPI()
  1. Add the token_authentication middleware to the FastAPI application:
  • app.middleware("http")(token_authentication)
  1. Define your API endpoints using FastAPI decorators and functions.
  2. Run the FastAPI application:
  • if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)

With these steps, you have configured and utilized token authentication in FastAPI using the custom middleware. The middleware intercepts incoming requests, validates the token against the Azure AD JWKS endpoint, and allows or denies access to the API endpoints based on the authentication status.

Content-Type Handling in FastAPI Middleware

Importance of handling content types, specifically JavaScript files

Handling content types is crucial in ensuring that the correct format and encoding are used when sending and receiving data over HTTP. Content types specify the type and format of the data being transferred, such as JSON, XML, HTML, plain text, or binary data.

In the case of JavaScript files, it is important to set the correct content type to ensure that the browser interprets and executes the JavaScript code correctly. Incorrect content types can lead to unexpected behavior and errors in the client-side execution of JavaScript code.

Overview of content-type negotiation in FastAPI

FastAPI provides built-in support for content-type negotiation, allowing API clients to specify the desired content type in the Accept header of their requests. FastAPI uses the Accept header to determine the appropriate content type to send in the response.

By default, FastAPI uses the Content-Type header to specify the content type in the response. However, in some cases, such as serving JavaScript files, we may need to override the default behavior and set the content type explicitly.

Role of the custom middleware in handling content types of JavaScript files

To handle the content types of JavaScript files in FastAPI, we can create a custom middleware that intercepts requests for JavaScript files and sets the appropriate content type header.

import os
from fastapi import FastAPI, Response
from fastapi.staticfiles import StaticFiles

def set_content_type(response: Response, filepath: str):
if filepath.endswith(".js"):
response.headers["Content-Type"] = "application/javascript"

app = FastAPI()

app.mount("/static", StaticFiles(directory="static"), name="static")
app.add_middleware(set_content_type)

In the code snippet above, we define a set_content_type function that is responsible for setting the content type header based on the file extension. If the filepath ends with the .js extension, it sets the Content-Type header to application/javascript.

Then, we create an instance of the FastAPI class and mount the /static path to the StaticFiles class. This allows FastAPI to serve static files from the static directory. Finally, we add the set_content_type middleware to the FastAPI application using the app.add_middleware method.

Sample code and explanation for implementing content-type handling in FastAPI

To implement content-type handling for JavaScript files in FastAPI, follow these steps:

  1. Import the required modules and classes:
  • from fastapi import FastAPI, Response from fastapi.staticfiles import StaticFiles
  1. Define the set_content_type function that sets the content type header based on the file extension:
  • def set_content_type(response: Response, filepath: str): if filepath.endswith(".js"): response.headers["Content-Type"] = "application/javascript"
  1. Create an instance of the FastAPI class:
  • app = FastAPI()
  1. Mount the /static path to the StaticFiles class to serve static files from the static directory:
  • app.mount("/static", StaticFiles(directory="static"), name="static")
  1. Add the set_content_type middleware to the FastAPI application:
  • app.add_middleware(set_content_type)
  1. Define your API endpoints using FastAPI decorators and functions.
  2. Run the FastAPI application:
  • if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)

With these steps, you have implemented content-type handling for JavaScript files in FastAPI using the custom middleware. The middleware intercepts requests for JavaScript files and sets the Content-Type header to application/javascript, ensuring that the browser interprets and executes the JavaScript code correctly.

Serving UI Files in FastAPI Middleware

Need for serving UI files and providing fallback for other requests in FastAPI

In many cases, FastAPI applications need to serve UI files, such as HTML, CSS, and JavaScript files, to provide a user interface for the API. Additionally, it is often desirable to serve a fallback, usually an index.html file, for any other requests that do not match a specific API endpoint or static file.

By serving UI files and providing a fallback for other requests, FastAPI can act as both an API backend and a frontend server, simplifying the deployment and management of applications.

Overview of serving static files in FastAPI applications

FastAPI provides built-in support for serving static files through the use of the StaticFiles class. The StaticFiles class allows you to define a directory from which FastAPI will serve static files, such as HTML, CSS, JavaScript, images, and more.

To serve static files using FastAPI, you need to create an instance of the StaticFiles class, mount it to a specific path, and configure the directory from which the static files will be served.

Integration of serving UI files and index.html fallback in the custom middleware

To serve UI files in FastAPI and provide a fallback for other requests, we can integrate the functionality into the custom middleware. The middleware intercepts requests and performs the following steps:

  1. Check if the requested file exists in the UI files directory.
  2. If the requested file exists, serve it as is.
  3. If the requested file does not exist, serve the index.html file as a fallback.
import os
from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from starlette.middleware import Middleware
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import FileResponse

class CustomMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
filepath = os.path.join("ui_files", request.url.path.lstrip("/"))
if os.path.isfile(filepath):
return FileResponse(filepath)
else:
return FileResponse(os.path.join("ui_files", "index.html"))

app = FastAPI(middleware=[Middleware(CustomMiddleware)])

app.mount("/static", StaticFiles(directory="static"), name="static")

In the code snippet above, we define a custom middleware class called CustomMiddleware that extends the BaseHTTPMiddleware class provided by Starlette. The CustomMiddleware class overrides the dispatch method, which is called for each incoming request.

In the dispatch method, we construct the filepath by joining the ui_files directory with the requested URL path. If the filepath exists as a file, we return a FileResponse with the file content. Otherwise, we return a FileResponse with the index.html file from the ui_files directory.

Finally, we create an instance of the FastAPI class and add the CustomMiddleware to the middleware parameter. We also mount the /static path to the StaticFiles class to serve static files from the static directory.

Demonstration of serving UI files with the custom middleware using sample code and instructions

To serve UI files and provide a fallback for other requests in FastAPI using the custom middleware, follow these steps:

  1. Import the required modules and classes:
  • import os from fastapi import FastAPI, Request from fastapi.staticfiles import StaticFiles from starlette.middleware import Middleware from starlette.middleware.base import BaseHTTPMiddleware from starlette.responses import FileResponse
  1. Define the CustomMiddleware class that extends the BaseHTTPMiddleware class:
  • class CustomMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): filepath = os.path.join("ui_files", request.url.path.lstrip("/")) if os.path.isfile(filepath): return FileResponse(filepath) else: return FileResponse(os.path.join("ui_files", "index.html"))
  1. Create an instance of the FastAPI class and add the CustomMiddleware to the middleware parameter:
  • app = FastAPI(middleware=[Middleware(CustomMiddleware)])
  1. Mount the /static path to the StaticFiles class to serve static files from the static directory:
  • app.mount("/static", StaticFiles(directory="static"), name="static")
  1. Define your API endpoints using FastAPI decorators and functions.
  2. Run the FastAPI application:
  • if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)

With these steps, you have implemented the custom middleware in FastAPI to serve UI files and provide a fallback for other requests. The middleware intercepts incoming requests, checks if the requested file exists in the ui_files directory, and serves it if it exists. If the requested file does not exist, it serves the index.html file.

Implementing the Custom Middleware in FastAPI

Introduction to the custom middleware class, ‘CustomMiddleware’

In the previous sections, we discussed the implementation of token authentication, content-type handling, and serving UI files in FastAPI using custom middleware. To summarize and provide a complete implementation, we can create a single custom middleware class called CustomMiddleware that incorporates all the functionalities.

The CustomMiddleware class extends the BaseHTTPMiddleware class provided by Starlette and overrides the dispatch method to implement the desired functionalities.

Explanation of the core logic of the ‘CustomMiddleware’ class

The CustomMiddleware class encapsulates the core logic of the middleware functionalities we discussed earlier.

In the dispatch method of the CustomMiddleware class:

  • For token authentication:
  • The method checks if the request URL starts with “/api” and if it contains an Authorization header with a valid token. If the conditions are met, the request is passed to the next middleware or the API endpoint itself. Otherwise, a 401 Unauthorized JSON response is returned.
  • For content-type handling:
  • When serving JavaScript files, the method sets the Content-Type header to application/javascript.
  • For serving UI files and providing a fallback:
  • The method checks if the requested file exists in the ui_files directory. If it does, the file is served as is. If the file does not exist, the index.html file from the ui_files directory is served as a fallback.
import os
from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from starlette.middleware import Middleware
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import JSONResponse, FileResponse

class CustomMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
if request.url.path.startswith("/api"):
token = request.headers.get("Authorization").split("Bearer ")[1]
if not validate_token(token):
return JSONResponse(status_code=401, content={"error": "Unauthorized"})

filepath = os.path.join("ui_files", request.url.path.lstrip("/"))
if os.path.isfile(filepath):
if filepath.endswith(".js"):
response = FileResponse(filepath)
response.headers["Content-Type"] = "application/javascript"
return response
else:
return FileResponse(filepath)
else:
return FileResponse(os.path.join("ui_files", "index.html"))

Sample code and instructions for implementing the custom middleware in FastAPI

To implement the custom middleware in FastAPI, follow these steps:

  1. Import the required modules and classes:
  • import os from fastapi import FastAPI, Request from fastapi.staticfiles import StaticFiles from starlette.middleware import Middleware from starlette.middleware.base import BaseHTTPMiddleware from starlette.responses import JSONResponse, FileResponse
  1. Define the CustomMiddleware class that extends the BaseHTTPMiddleware class and overrides the dispatch method:
  • class CustomMiddleware(BaseHTTPMiddleware): async def dispatch(self, request: Request, call_next): if request.url.path.startswith("/api"): token = request.headers.get("Authorization").split("Bearer ")[1] if not validate_token(token): return JSONResponse(status_code=401, content={"error": "Unauthorized"}) filepath = os.path.join("ui_files", request.url.path.lstrip("/")) if os.path.isfile(filepath): if filepath.endswith(".js"): response = FileResponse(filepath) response.headers["Content-Type"] = "application/javascript" return response else: return FileResponse(filepath) else: return FileResponse(os.path.join("ui_files", "index.html"))
  1. Create an instance of the FastAPI class and add the CustomMiddleware to the middleware parameter:
  • app = FastAPI(middleware=[Middleware(CustomMiddleware)])
  1. Mount the /static path to the StaticFiles class to serve static files from the static directory:
  • app.mount("/static", StaticFiles(directory="static"), name="static")
  1. Define your API endpoints using FastAPI decorators and functions.
  2. Run the FastAPI application:
  • if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)

With these steps, you have implemented the custom middleware in FastAPI, incorporating the functionalities of token authentication, content-type handling, and serving UI files. The middleware intercepts incoming requests, performs the necessary checks and actions based on the request characteristics, and returns the appropriate responses.

Conclusion

In this article, we explored the top 10 FastAPI middleware solutions for optimizing your application. We discussed the benefits of FastAPI and the role of middleware in extending its functionality. We also highlighted the importance of custom middleware for adding specific functionalities to FastAPI applications.

We covered the implementation of token authentication in FastAPI using Azure AD JWKS endpoint for token validation. We provided step-by-step instructions and sample code for configuring and utilizing token authentication in FastAPI.

We also discussed the importance of handling content types, specifically JavaScript files, in FastAPI middleware. We explained the content-type negotiation feature in FastAPI and demonstrated the implementation of content-type handling using a custom middleware.

Furthermore, we explored the need for serving UI files and providing a fallback for other requests in FastAPI. We described the built-in support for serving static files in FastAPI and provided a custom middleware that integrates the serving of UI files and the index.html fallback.

Finally, we provided a complete implementation of the custom middleware in FastAPI, which includes token authentication, content-type handling, and serving UI files functionalities. We explained the core logic of the middleware class and provided sample code and instructions for implementing it in a FastAPI application.

By leveraging these top 10 FastAPI middleware solutions, you can optimize your application, enhance its capabilities, and provide a secure and efficient experience for your API users.

Looking for a Postman alternative?

Try APIDog, the Most Customizable Postman Alternative, where you can connect to thousands of APIs right now!

--

--

Jennie Lee
Jennie Lee

Written by Jennie Lee

Software Testing Blogger, #API Testing

No responses yet