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
offenses_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.5.tar.gz (8.3 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.5-py3-none-any.whl (9.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: fastapi_easylimiter-0.3.5.tar.gz
  • Upload date:
  • Size: 8.3 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.5.tar.gz
Algorithm Hash digest
SHA256 f029a5d03118dbdc757617cf03c7be6bbbc43e826f3266a998dd898a0bbf7506
MD5 d91ef3faed731d0798017b74560d89aa
BLAKE2b-256 e639f0a0a7e03201ac9b4812a2e2990b831721cc9306a846a98af02a0f3cdf6e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for fastapi_easylimiter-0.3.5-py3-none-any.whl
Algorithm Hash digest
SHA256 c538dab7ef00ab19e6216aa505030d4c245c2dca2418ec6192fd07215429556e
MD5 a04b38bb8683544d103b5d892cd6ee23
BLAKE2b-256 66ba66f62b197d949b3153ee2b4e40c06ac7955cd50222fee18bd80015b6edcd

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