Skip to content

API Rate Limiter

CarterPerez-dev edited this page Feb 11, 2026 · 1 revision

API Rate Limiter

Production-ready rate limiting library for FastAPI with three algorithms, three-layer defense, and advanced client fingerprinting.

Overview

fastapi-420 is a rate limiting library implementing sliding window, token bucket, and fixed window algorithms with Redis or in-memory storage. Features a three-layer defense system (per-user, per-endpoint, global DDoS protection), advanced client fingerprinting with IPv6 /64 normalization, and atomic Lua scripts for correctness under concurrent load.

Status: Complete | Difficulty: Advanced

Tech Stack

Technology Version Purpose
Python 3.12+ Async/await throughout
FastAPI - ASGI web framework
Redis 7+ Distributed storage backend
Pydantic v2 Settings validation
Lua scripts - Atomic Redis operations

Features

Rate Limiting Algorithms

Algorithm Accuracy Memory Best For
Sliding Window 99.997% Constant Production default
Token Bucket Exact Constant Burst tolerance
Fixed Window ~Exact Constant Simple use cases (has boundary exploit)

Three-Layer Defense

  1. Per-User Limits β€” Stop individual abuse
  2. Per-Endpoint Limits β€” Prevent endpoint-specific attacks
  3. Global Limits β€” DDoS protection with circuit breaker

Client Fingerprinting

  • IP extraction with proxy-aware X-Forwarded-For handling
  • IPv6 /64 block normalization (prevents trivial bypass)
  • User-Agent and Accept header analysis
  • JWT/API key/session identity extraction
  • Composite fingerprinting combining all methods

Response Headers

HTTP/1.1 420 Enhance Your Calm
Retry-After: 42
RateLimit-Limit: 100
RateLimit-Remaining: 0
RateLimit-Reset: 1706900000

Security Relevance

  • GitHub 1.35 Tbps DDoS (2018) β€” rate limiting enabled 10-minute recovery
  • Dunkin' Donuts credential stuffing (2019) β€” login rate limits block this
  • PS5 scalper bots (2020) β€” checkout rate limits for fair access

Architecture

Incoming Request
    ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         ASGI Middleware (middleware.py)        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚      Client Fingerprinting (composite.py)    β”‚
β”‚  IP + Headers + Auth β†’ Composite Key         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         Three-Layer Defense (layers.py)       β”‚
β”‚  User Layer β†’ Endpoint Layer β†’ Global Layer  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                       ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Sliding    β”‚    Token     β”‚    Fixed     β”‚
β”‚   Window     β”‚    Bucket    β”‚    Window    β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Redis      β”‚   In-Memory  β”‚
β”‚   Backend    β”‚   Backend    β”‚
β”‚  (Lua atomic)β”‚  (asyncio)   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Quick Start

cd PROJECTS/advanced/api-rate-limiter

# Install dependencies
uv sync

# Optional: Start Redis
docker run -d -p 6379:6379 redis:7-alpine

# Run the example app
uv run python examples/app.py

# Test rate limiting
curl http://localhost:8000/auth/login -X POST -d "username=test&password=test"
# After 3 requests: HTTP/1.1 420 Enhance Your Calm

Configuration

# Redis (production)
REDIS_URL=redis://localhost:6379

# Fallback to in-memory when Redis unavailable
FALLBACK_TO_MEMORY=True

# Trust proxy headers
TRUST_X_FORWARDED_FOR=True

# Circuit breaker threshold
CIRCUIT_THRESHOLD=1000

Project Structure

api-rate-limiter/
β”œβ”€β”€ src/fastapi_420/
β”‚   β”œβ”€β”€ algorithms/           # Rate limiting algorithms
β”‚   β”‚   β”œβ”€β”€ sliding_window.py
β”‚   β”‚   β”œβ”€β”€ token_bucket.py
β”‚   β”‚   └── fixed_window.py
β”‚   β”œβ”€β”€ storage/              # Storage backends
β”‚   β”‚   β”œβ”€β”€ memory.py         # In-memory (single instance)
β”‚   β”‚   β”œβ”€β”€ redis_backend.py  # Redis (distributed)
β”‚   β”‚   └── lua/              # Atomic Lua scripts
β”‚   β”œβ”€β”€ fingerprinting/       # Client identification
β”‚   β”‚   β”œβ”€β”€ ip.py             # IP + IPv6 /64 normalization
β”‚   β”‚   β”œβ”€β”€ headers.py        # User-Agent, Accept-*
β”‚   β”‚   β”œβ”€β”€ auth.py           # JWT, API keys, sessions
β”‚   β”‚   └── composite.py      # Combined fingerprint
β”‚   β”œβ”€β”€ defense/              # Multi-layer protection
β”‚   β”‚   β”œβ”€β”€ layers.py         # User/Endpoint/Global limits
β”‚   β”‚   └── circuit_breaker.py
β”‚   β”œβ”€β”€ limiter.py            # Main RateLimiter class
β”‚   β”œβ”€β”€ middleware.py          # ASGI middleware
β”‚   β”œβ”€β”€ dependencies.py       # FastAPI dependency injection
β”‚   β”œβ”€β”€ config.py             # Pydantic settings
β”‚   └── types.py              # Data structures
β”œβ”€β”€ examples/
β”‚   └── app.py                # Full working example
└── tests/

Development

# Run tests
uv run pytest tests/ -v

# Linting
uv run ruff check .

# Type checking
uv run mypy src/

# Format
uv run ruff format .

Source Code

View on GitHub

Clone this wiki locally