Flexible rate limiting for FastAPI using pyrate-limiter
Project description
fapi-limiter
Flexible rate limiting for FastAPI powered by pyrate-limiter.
This project is being developed with AI assistance (GitHub Copilot), but all code, design decisions, and implementation details are reviewed and validated by the author.
Installation
# pip
pip install fapi-limiter
# uv
uv add fapi-limiter
Usage
Middleware (app-wide)
Apply rate limiting to every request in the application.
from fastapi import FastAPI
from pyrate_limiter import Duration, Limiter, Rate
from fapi_limiter import DynamicBucketFactory, RateLimiterMiddleware, setup_inmemory_bucket
app = FastAPI()
limiter = Limiter(DynamicBucketFactory(setup_inmemory_bucket([Rate(10, Duration.MINUTE)])))
app.add_middleware(RateLimiterMiddleware, limiter=limiter)
Dependency (per-route)
Apply rate limiting to specific routes using FastAPI's dependency injection.
from fastapi import Depends, FastAPI
from pyrate_limiter import Duration, Limiter, Rate
from fapi_limiter import DynamicBucketFactory, RateLimiter, setup_inmemory_bucket
app = FastAPI()
limiter = Limiter(DynamicBucketFactory(setup_inmemory_bucket([Rate(10, Duration.MINUTE)])))
@app.get("/limited", dependencies=[Depends(RateLimiter(limiter))])
def limited():
return {"ok": True}
SQLite backend (persistent, multi-process)
from fastapi import FastAPI
from pyrate_limiter import Duration, Limiter, Rate
from fapi_limiter import DynamicBucketFactory, RateLimiterMiddleware, setup_sqlite_bucket
app = FastAPI()
limiter = Limiter(
DynamicBucketFactory(
setup_sqlite_bucket(
[Rate(10, Duration.MINUTE)],
db_path="rate_limiter.db",
use_file_lock=True, # required when sharing across processes
)
)
)
app.add_middleware(RateLimiterMiddleware, limiter=limiter)
Redis backend
from fastapi import FastAPI
from pyrate_limiter import Duration, Limiter, Rate
from redis import Redis
from fapi_limiter import DynamicBucketFactory, RateLimiterMiddleware, setup_redis_bucket
app = FastAPI()
limiter = Limiter(
DynamicBucketFactory(
setup_redis_bucket([Rate(10, Duration.MINUTE)], redis=Redis(host="localhost"))
)
)
app.add_middleware(RateLimiterMiddleware, limiter=limiter)
Response Headers
On every request, the following headers are set:
| Header | Description |
|---|---|
X-RateLimit-Limit |
Maximum requests allowed in the window |
X-RateLimit-Remaining |
Requests remaining in the current window |
X-RateLimit-Reset |
Unix timestamp (ms) when the window resets |
When the limit is exceeded, 429 Too Many Requests is returned and two additional headers are set:
| Header | Description |
|---|---|
Retry-After |
Unix timestamp (ms) after which the client may retry |
Configuration
Both RateLimiterMiddleware and RateLimiter accept the same options:
| Parameter | Type | Default | Description |
|---|---|---|---|
limiter |
Limiter |
required | A pyrate-limiter Limiter instance |
callback |
CallbackFunction |
default_callback |
Called when the limit is exceeded |
identifier |
Callable[[Request], str] |
get_default_identifier |
Extracts a key from the request (e.g. IP + path) |
blocking |
bool |
False |
Whether to block and wait instead of rejecting |
RateLimiterMiddleware also accepts:
| Parameter | Type | Default | Description |
|---|---|---|---|
skip |
SkipFunction | None |
None |
If it returns True, the request bypasses rate limiting |
Custom Callback
The callback is invoked when a request is rate-limited. It receives the Request and a headers dict, and should raise an HTTPException:
from fastapi import HTTPException, Request
from fapi_limiter import RateLimiterMiddleware
def my_callback(request: Request, headers=None):
raise HTTPException(status_code=429, detail="Slow down!", headers=headers)
app.add_middleware(RateLimiterMiddleware, limiter=limiter, callback=my_callback)
Custom Identifier
By default the identifier is {request_method}:{client_ip}:{path}. You can override it to key by user, API token, etc.:
def by_user(request: Request) -> str:
return request.headers.get("X-User-Id", "anonymous") + ":" + request.url.path
app.add_middleware(RateLimiterMiddleware, limiter=limiter, identifier=by_user)
Skip Function
Use skip on RateLimiterMiddleware to bypass rate limiting for certain requests (e.g. health checks):
def skip_health(request: Request) -> bool:
return request.url.path == "/health"
app.add_middleware(RateLimiterMiddleware, limiter=limiter, skip=skip_health)
Credits
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fapi_limiter-0.2.0.tar.gz.
File metadata
- Download URL: fapi_limiter-0.2.0.tar.gz
- Upload date:
- Size: 7.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c5c439da21acf8464bdbc801cf8ceef92315d532ff4abe5e988bf6b8a9ff915d
|
|
| MD5 |
98b143a88125e7c91208fb40c3d7d390
|
|
| BLAKE2b-256 |
dc384132442ed3cc2c1e3add3ed8a9f6c9551d0db120ceed91f8e09c55c96a2f
|
File details
Details for the file fapi_limiter-0.2.0-py3-none-any.whl.
File metadata
- Download URL: fapi_limiter-0.2.0-py3-none-any.whl
- Upload date:
- Size: 10.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fc94b6e487daf0ad667fa2a1429b17c50dd3231ff80bec7d405076d8d7c685df
|
|
| MD5 |
ffa9e53504bc97b2d845dd406580609e
|
|
| BLAKE2b-256 |
a2ab46e56a964de46a720d173a3ed5f5fd2b625c951a55020de47d27d4c2cf9d
|