Skip to main content

Async rate limiter for FastAPI with Redis or native in-memory backend

Project description

fastapi‑easylimiter

GitHub stars GitHub forks GitHub issues GitHub license PyPI


An ASGI async rate-limiting middleware for FastAPI with Redis or in-memory caching, designed to handle auto-generated routes (e.g., FastAPI-Users) without decorators, for simplicity and performance.


Features

  • Async rate limiting
  • Optional temporary IP bans
    • Configurable threshold (default 10 violations)
    • Sliding 30-min offense window
    • 5-min ban on repeat abuse
  • Cache Backends
    • Redis (recommended for multi-instance deployments)
    • In-Memory (single worker dev)
  • Path-based rules
    • Supports multi-rule prefix matching
    • Global and per-route limits
  • Standard rate-limit headers
    • X-RateLimit-Limit
    • X-RateLimit-Remaining
    • X-RateLimit-Reset
    • Retry-After on 429 responses
  • Proxy Aware
    • Uses 'X-Forwarded-For' only when the sender is trusted
    • Rejects spoofed XFF headers
    • Supports 'CF-Connecting-IP' from Cloudflare, verified against CF CIDRs
    • Fallback to ASGI scope["client"] if no trusted headers exist
  • Zero dependencies beyond Redis client
    • Starlette-style ASGI middleware
  • Custom responses
    • HTMLResponse for browser clients
    • JSONResponse for API clients

Installation

pip install fastapi-easylimiter

Usage

from fastapi import FastAPI
from fastapi_easylimiter import AsyncRedisBackend, InMemoryBackend, RateLimiterMiddleware
import redis.asyncio as redis_async

app = FastAPI()

REDIS_URL = "redis://localhost:6379/0"

# Redis backend (recommended for multi-instance deployments)
redis_client = redis_async.from_url(REDIS_URL, decode_responses=True)
backend = AsyncRedisBackend(redis_client)

# Or for single-instance/local development:
# backend = InMemoryBackend()

rules = {
    "/": {"limit": 600, "period": 60},          # GLOBAL: 600 req/min per IP
    "/api/": {"limit": 10, "period": 1},
    "/api/users": {"limit": 1, "period": 2},
}

app.add_middleware(
    RateLimiterMiddleware,
    rules=rules,
    backend=backend,
    trusted_proxies=[""],     # OPTIONAL: your proxy IPs
    cloudflare=False,         # OPTIONAL: enable CF-Connecting-IP
    enable_bans=True,         # OPTIONAL: enable temporary bans
    ban_threshold=15,         # Violations before ban
    ban_duration=300,         # Ban length in seconds
    offenses_ttl=900,         # Offense counting window
    ban_page="<p>Your IP has been temporarily banned.</p>",        # OPTIONAL custom HTML ban page
    rate_page="<p>Too many requests. Please try again later.</p>", # OPTIONAL custom HTML rate-limit page
)

Example: /api/users/me matches /api/users and /api. If any rule is exceeded → 429 returned.


Redis Lua Script

local key = KEYS[1]
local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local now = tonumber(ARGV[3])

local count = redis.call("INCR", key)
local ttl = redis.call("TTL", key)

if count == 1 or ttl < 0 then
    redis.call("EXPIRE", key, window)
    ttl = window
end

local reset = now + ttl
local exceeded = count > limit and 1 or 0

return {count, reset, exceeded}

Redis Key Patterns

Key Pattern Example Purpose
rl:{client_ip}:{prefix} rl:203.0.113.5:/api Rate-limit counter per IP+prefix
ban:{client_ip} ban:203.0.113.5 Temporary ban
offenses:{client_ip} offenses:203.0.113.5 Offense counter for ban tracking

Middleware Parameters

Parameter Type Description
app ASGIApp FastAPI/ASGI app
rules dict { prefix: {"limit": int, "period": int} }
backend Redis or InMemory backend Rate-limit storage
trusted_proxies list[str] Proxies allowed to trust XFF headers
cloudflare bool Enable Cloudflare IP extraction
enable_bans bool Enable temporary IP bans
ban_threshold int Violations before ban
ban_duration int Ban length in seconds
offense_ttl int Offense counting window in seconds
ban_page str Custom HTML ban page
rate_page str Custom HTML rate-limit page

Screenshot

fastapi-easylimiter screenshot

Contributing

Contributions and forks are always welcome! Adapt, improve, or extend for your own needs.


Support

Buy Me a Coffee


Parts of this code were generated/assisted by AI (Grok).

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastapi_easylimiter-0.3.6.tar.gz (8.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastapi_easylimiter-0.3.6-py3-none-any.whl (10.0 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_easylimiter-0.3.6.tar.gz.

File metadata

  • Download URL: fastapi_easylimiter-0.3.6.tar.gz
  • Upload date:
  • Size: 8.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.1

File hashes

Hashes for fastapi_easylimiter-0.3.6.tar.gz
Algorithm Hash digest
SHA256 f580f9f5abfa8a414f7a4f2b9cdc3bd1aeb3a63f1966830cbf0f87715bb19e5b
MD5 bfa4e862a53c518dff538a425c5854a5
BLAKE2b-256 44b993075acf676d7623f1a325295fc77a29d027abfa818b1abdf64be146dd49

See more details on using hashes here.

File details

Details for the file fastapi_easylimiter-0.3.6-py3-none-any.whl.

File metadata

File hashes

Hashes for fastapi_easylimiter-0.3.6-py3-none-any.whl
Algorithm Hash digest
SHA256 2d733b9edbdb5053a423707defbfedb5dc8dd2982f683c339a988ffe46dae795
MD5 8ece9cd2e061c0f566062bfdb5cbb1e2
BLAKE2b-256 29b7ee79b3d85aae9a33030661be54c9d49b21f09c758512e20755caa9f8fe3c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page