Skip to main content

FastAPI Compression Middleware

Introduction

When building web applications, optimizing data transfer between servers and clients is critical for performance. One effective technique is compression - reducing the size of responses before they're sent over the network. FastAPI provides built-in support for response compression through middleware.

In this tutorial, you'll learn:

  • What compression middleware is and why it matters
  • How to implement compression in FastAPI
  • How to configure compression settings
  • Best practices and performance considerations

What is Compression Middleware?

Compression middleware intercepts HTTP responses before they're sent to the client and compresses them using algorithms like gzip, deflate, or brotli. This can significantly reduce the amount of data transferred over the network, leading to faster page loads and better user experience.

When a client (like a web browser) supports compression, it will include an Accept-Encoding header in its request. The server then uses this information to determine if and how to compress the response.

Why Use Compression?

Several benefits make compression middleware worth implementing:

  1. Reduced bandwidth usage - Compressed responses are typically 70-90% smaller
  2. Faster load times - Less data to transfer means quicker page loads
  3. Lower hosting costs - Reduced bandwidth consumption can lead to savings
  4. Better mobile experience - Especially important for users on limited data plans

Implementing Compression in FastAPI

FastAPI uses Starlette's GZipMiddleware for compression. Let's look at how to implement it:

Basic Implementation

python
from fastapi import FastAPI
from fastapi.middleware.gzip import GZipMiddleware

app = FastAPI()

# Add compression middleware
app.add_middleware(GZipMiddleware, minimum_size=1000)

@app.get("/")
async def root():
return {"message": "This response will be compressed if large enough!"}

This simple example adds gzip compression to all responses larger than 1000 bytes. The client must support gzip compression (indicated by sending Accept-Encoding: gzip in the request headers).

Testing Compression

You can verify if compression is working by examining the response headers. When compression is applied, you'll see a Content-Encoding: gzip header in the response.

Let's create a route that returns a large response to demonstrate compression:

python
@app.get("/large-response")
async def get_large_response():
# Generate a large text response
large_data = "Hello, World! " * 1000
return {"data": large_data}

When you access this endpoint with a browser or a tool like curl with the appropriate headers, you'll receive a compressed response:

bash
curl -H "Accept-Encoding: gzip" http://localhost:8000/large-response -i

The response should include:

HTTP/1.1 200 OK
content-encoding: gzip
...

Configuring Compression Options

The GZipMiddleware accepts several parameters to fine-tune its behavior:

python
app.add_middleware(
GZipMiddleware,
minimum_size=1000, # Only compress responses larger than this (in bytes)
compresslevel=9 # Compression level (1-9, where 9 is highest but slowest)
)

Options Explained

  • minimum_size: Sets the threshold for compression. Responses smaller than this value won't be compressed, as the overhead might outweigh the benefits.
  • compresslevel: Controls the compression ratio and processing time:
    • Lower values (1-3): Faster compression but larger file sizes
    • Higher values (7-9): Slower compression but smaller file sizes
    • Middle values (4-6): A balance between speed and size

Real-World Examples

Let's explore some practical examples of when to use compression middleware.

Example 1: API Serving Large JSON Responses

python
from fastapi import FastAPI
from fastapi.middleware.gzip import GZipMiddleware
import json

app = FastAPI()
app.add_middleware(GZipMiddleware, minimum_size=500)

# Load a large dataset
with open("large_dataset.json", "r") as file:
large_dataset = json.load(file)

@app.get("/api/products")
async def get_products():
# This large JSON response will benefit from compression
return large_dataset

Example 2: Text-Heavy Web Application

python
from fastapi import FastAPI, Request
from fastapi.middleware.gzip import GZipMiddleware
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates

app = FastAPI()
app.add_middleware(GZipMiddleware, minimum_size=1000)

templates = Jinja2Templates(directory="templates")

@app.get("/article/{article_id}", response_class=HTMLResponse)
async def read_article(request: Request, article_id: str):
# HTML responses are typically very compressible
article_content = get_article_content(article_id) # Function to fetch article
return templates.TemplateResponse(
"article.html",
{"request": request, "content": article_content}
)

Performance Considerations

While compression is beneficial in many cases, it's important to consider these factors:

CPU Usage

Compression requires computational resources. For high-traffic applications, this can impact server performance. Consider these guidelines:

  • For low-traffic sites, use higher compression levels (7-9)
  • For high-traffic sites, use moderate compression (4-6)
  • Set reasonable minimum sizes to avoid compressing small responses

Content Types

Some content types benefit more from compression than others:

  • Highly compressible: HTML, JSON, XML, CSS, JavaScript, plain text
  • Moderately compressible: Some image formats, structured binary data
  • Already compressed: JPEG, PNG, GIF, modern video formats, ZIP files

For already compressed formats, applying compression middleware is unnecessary and wastes CPU resources. You can selectively apply compression based on content type:

python
from fastapi import FastAPI, Request, Response
from fastapi.middleware.base import BaseHTleware
from gzip import compress

class SelectiveCompressionMiddleware(BaseHTleware):
async def dispatch(self, request: Request, call_next):
response = await call_next(request)

# Check if client accepts gzip encoding
if "gzip" in request.headers.get("Accept-Encoding", ""):
content_type = response.headers.get("Content-Type", "")

# Only compress compressible content types
if any(ct in content_type for ct in ["text/", "application/json", "application/xml"]):
# Get response body
body = b""
async for chunk in response.body_iterator:
body += chunk

# Only compress if large enough
if len(body) > 1000:
compressed_body = compress(body)
# Create new response with compressed data
new_response = Response(
content=compressed_body,
status_code=response.status_code,
headers=dict(response.headers),
media_type=response.media_type
)
new_response.headers["Content-Encoding"] = "gzip"
new_response.headers["Content-Length"] = str(len(compressed_body))
return new_response

return response

app = FastAPI()
app.add_middleware(SelectiveCompressionMiddleware)

This is a more complex example, but shows how you could implement custom compression logic.

Browser Support

Modern browsers all support gzip compression, so it's safe to implement in most applications. They indicate this support through the Accept-Encoding header in their requests.

Summary

FastAPI's compression middleware offers an easy way to improve your application's performance by reducing the size of HTTP responses. Key takeaways include:

  • Compression can significantly reduce bandwidth usage and improve load times
  • Implementation is straightforward with GZipMiddleware
  • Configure compression settings based on your application's needs
  • Consider performance implications for high-traffic applications
  • Be mindful of content types that don't benefit from compression

By implementing compression middleware appropriately, you can enhance your FastAPI application's performance and user experience with minimal effort.

Additional Resources

Exercises

  1. Implement basic compression middleware in a FastAPI application and test it with different compression levels.
  2. Create a route that returns a large JSON payload and measure the response size with and without compression.
  3. Implement custom middleware that only compresses specific content types.
  4. Set up load testing to evaluate the performance impact of different compression settings on your application.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)