Skip to content

FastAPI Rate Limiting — API Throttling with SlowAPI Middleware

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about FastAPI Rate Limiting. We cover key concepts, practical examples, and best practices to help you master this topic.

SlowAPI is an async-compatible rate limiting library for FastAPI and Starlette that provides decorator-based and middleware-based rate limiting with support for multiple backends including Redis.

What You'll Learn

  • How to install and configure SlowAPI with FastAPI
  • How to apply rate limits per-endpoint and globally
  • How to use Redis for distributed rate limiting

Why It Matters

FastAPI is the leading Python async web framework. SlowAPI integrates natively with FastAPI's dependency injection system, providing type-safe rate limiting that works seamlessly with async handlers and Websocket endpoints.

Real-World Use

DodaTech's FastAPI microservice uses SlowAPI with three rate limit configurations: global middleware (100 req/min), auth endpoints (5 req/min via dependency), and data endpoints (30 req/min per user). Redis backend ensures consistent limits across multiple uvicorn workers.

flowchart LR
    A["Request"] --> B["SlowAPI\nMiddleware"]
    B --> C{"Global limit\n100/min"}
    C -->|"OK"| D{"Auth endpoint\n5/min"}
    D -->|"OK"| E["Route Handler"]
    C -->|"Exceeded"| F["429 Response"]
    D -->|"Exceeded"| F
    style B fill:#dbeafe,stroke:#2563eb
    style D fill:#fef3c7,stroke:#d97706
    style F fill:#fecaca,stroke:#dc2626

Global Middleware Configuration

from fastapi import FastAPI, Request
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
from slowapi.middleware import SlowAPIMiddleware

limiter = Limiter(key_func=get_remote_address)
app = FastAPI()

app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
app.add_middleware(SlowAPIMiddleware)

@app.get("/api/data")
@limiter.limit("100/minute")
async def get_data(request: Request):
    return {"data": "response data"}

Per-Endpoint Limits

from slowapi import Limiter
from slowapi.util import get_remote_address

limiter = Limiter(key_func=get_remote_address)

@app.post("/api/auth/login")
@limiter.limit("5/minute")
async def login(request: Request, username: str = Form(...), password: str = Form(...)):
    return {"status": "authenticated"}

@app.get("/api/public/search")
@limiter.limit("30/minute")
async def search(request: Request, q: str = Query(...)):
    return {"results": search_database(q)}

@app.get("/api/admin/users")
@limiter.limit("100/minute")
async def admin_users(request: Request):
    return {"users": get_all_users()}

User-Based Rate Limiting

from slowapi import Limiter
from fastapi import Depends, HTTPException, status

def get_user_key(request: Request):
    """Extract user identifier for rate limiting"""
    api_key = request.headers.get("X-API-Key")
    if api_key:
        return f"apikey:{api_key}"
    return get_remote_address(request)

limiter = Limiter(key_func=get_user_key)

@app.get("/api/v2/data")
@limiter.limit("1000/minute")
async def v2_data(request: Request, api_key: str = Depends(validate_api_key)):
    return {"data": "v2 response"}

Redis Backend

from slowapi import Limiter
from slowapi.middleware import SlowAPIMiddleware
import aioredis

# Install: pip install slowapi[redis]

limiter = Limiter(
    key_func=get_remote_address,
    storage_uri="redis://redis-cluster.dodatech.com:6379/0"
)

app = FastAPI()
app.state.limiter = limiter
app.add_middleware(SlowAPIMiddleware)
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)

# Custom error response
@app.exception_handler(RateLimitExceeded)
async def custom_rate_limit_handler(request: Request, exc: RateLimitExceeded):
    return JSONResponse(
        status_code=429,
        content={
            "error": "rate_limit_exceeded",
            "message": str(exc),
            "retry_after": 60
        },
        headers={
            "X-RateLimit-Retry-After": "60"
        }
    )

Common Mistakes

1. Not Adding the Middleware

The @limiter.limit() decorator requires the SlowAPIMiddleware to be added. Without it, the decorator has no effect.

2. Forgetting the request Parameter

The decorated endpoints must accept a request: Request parameter, even if not used. SlowAPI uses it for key extraction.

3. Using get_remote_address Behind a Proxy

Behind a reverse proxy, get_remote_address returns the proxy IP. Use a custom key function that reads the X-Forwarded-For header.

4. Not Customizing Error Responses

The default error response is minimal. Customize the RateLimitExceeded exception handler for user-friendly messages.

5. Applying Limits to WebSocket Endpoints

WebSocket rate limiting requires careful handling. SlowAPI supports it, but the connection lifecycle is different from HTTP.

Practice Questions

  1. What library provides FastAPI rate limiting?
  2. How do you apply a rate limit to a specific endpoint?
  3. What is the key_func parameter used for?
  4. How do you set up Redis as the rate limit backend?
  5. Why must the request parameter be present in decorated endpoints?

Answers

  1. SlowAPI. 2. Use the @limiter.limit("N/period") decorator. 3. To determine the identifier for rate limiting (IP, user, API key). 4. Set storage_uri="redis://host:port/db" when creating the Limiter. 5. SlowAPI extracts the rate limit key from the request object.

Challenge

Build a FastAPI application with SlowAPI rate limiting that: uses Redis backend for distributed limiting, has four rate limit levels (public 30/min, auth 5/min, standard 100/min, premium 1000/min), uses custom key functions for user-based and API-key-based limiting, and returns custom 429 JSON responses with upgrade suggestions.

FAQ

What is SlowAPI?

An async-compatible rate limiting library for FastAPI and Starlette.

Does SlowAPI support distributed rate limiting?

Yes, with Redis, Memcached, or MongoDB backends.

Can I use different limits for different HTTP methods?

Yes, by applying different @limiter.limit() decorators per method.

Is SlowAPI compatible with WebSocket?

Yes, but requires specific configuration for WebSocket rate limiting.

How do I customize rate limit error messages?

Register a custom exception handler for RateLimitExceeded.

Mini Project

Create a FastAPI application with: a global SlowAPI middleware (50 req/min per IP), per-endpoint decorators for auth (5/min), search (30/min), and admin (100/min) endpoints, Redis backend for multi-worker consistency, custom key functions for API key extraction, and a comprehensive test suite with httpx AsyncClient.

What's Next

  • Build the complete rate limiting project combining all concepts
  • Explore rate limit headers and client-side handling
  • Continue to rate limit monitoring with Prometheus and Grafana

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro