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
Metadata
Release files for fapi-limiter 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fapi_limiter-0.2.0.tar.gz | 7.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fapi_limiter-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 17.9 kB
Release files / fapi_limiter-0.2.0.tar.gz
| Download URL | fapi_limiter-0.2.0.tar.gz |
|---|---|
| Size | 7.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c5c439da21acf8464bdbc801cf8ceef92315d532ff4abe5e988bf6b8a9ff915d
|
|
BLAKE2b-256 checksum How to use checksums |
dc384132442ed3cc2c1e3add3ed8a9f6c9551d0db120ceed91f8e09c55c96a2f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|
Release files / fapi_limiter-0.2.0-py3-none-any.whl
| Download URL | fapi_limiter-0.2.0-py3-none-any.whl |
|---|---|
| Size | 10.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fc94b6e487daf0ad667fa2a1429b17c50dd3231ff80bec7d405076d8d7c685df
|
|
BLAKE2b-256 checksum How to use checksums |
a2ab46e56a964de46a720d173a3ed5f5fd2b625c951a55020de47d27d4c2cf9d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|