FastAPI rate limiter
This package adds a rate limiter to FastAPI using Redis.
Installation
First install Redis, then install the package using:
pip install fastapi-user-limiter
Usage
All the examples below can be found in example.py (use uvicorn example:app --reload to run).
Single and multiple rate limiters
You can use the rate_limit function as a FastAPI Dependency to add one or several rate limiters to an endpoint:
from fastapi_user_limiter.limiter import rate_limiter
from fastapi import FastAPI, Depends
app = FastAPI()
# Max 2 requests per 5 seconds
@app.get("/single",
dependencies=[Depends(rate_limiter(2, 5))])
async def read_single():
return {"Hello": "World"}
# Max 1 requests per second and max 3 requests per 10 seconds
@app.get("/multi/{some_param}", dependencies=[
Depends(rate_limiter(1, 1)),
Depends(rate_limiter(3, 10))
])
async def read_multi(some_param: str):
return {"Hello": f"There {some_param}"}
Router/API-wide rate limits
You can also add a router-wide (or even API-wide) rate limiter that applies to all endpoints taken together, rather than per-endpoint:
from fastapi_user_limiter.limiter import rate_limiter
from fastapi import Depends, APIRouter
# The rate limiter in the router applies to the two endpoints together.
# If a request is made to /single, a request to /single2 within the next
# 3 seconds will result in a "Too many requests" error.
# This rate limiter must have a custom path value, preferably
# the same as the router's prefix value.
router = APIRouter(
prefix='/router',
dependencies=[Depends(rate_limiter(1, 3,
path='/router'))]
)
# Each endpoint also has its own, separate rate limiter
@router.get("/single",
dependencies=[Depends(rate_limiter(3, 20))])
async def read_single_router():
return {"Hello": "World"}
@router.get("/single2",
dependencies=[Depends(rate_limiter(5, 60))])
async def read_single2_router():
return {"Hello": "There"}
Per-user rate limits
By default, rate limits are applied per host (i.e. per IP address). However,
you may want to apply the rate limits on a per-user basis, especially if your
API has authentication. To do so, you can pass a custom async callable to the
user argument of rate_limiter, which extracts the username from the request
headers:
from fastapi_user_limiter.limiter import rate_limiter
from fastapi import Depends, FastAPI
app = FastAPI()
def get_user(headers, path):
# The username is assumed to be a bearer token,
# contained in the 'authorization' header.
username = headers['authorization'].replace('Bearer ', '')
return username
# 3 requests max per 20 seconds, per user
@app.post("/auth",
dependencies=[Depends(rate_limiter(3, 20,
user=get_user))])
async def read_with_auth(data: dict):
return {'input': data}
User-based rate limit overrides
The async callable introduced above can be used to override max_requests
and/or window values for specific users by returning a dict instead of
a str. In the example below, the callable overrides and increases the
value of max_requests for the user "admin" and for the endpoint
/auth:
from fastapi_user_limiter.limiter import rate_limiter
from fastapi import Depends, FastAPI
from starlette.datastructures import Headers, URL
app = FastAPI()
# The user callable can return either of these two:
# A. One single string containing the username
# B. A dictionary that maps the key "username" to the username (obligatory), plus two optional keys:
# i. "max_requests": overriding the endpoint's original max_requests value for this particular user
# ii. "window": overriding the endpoint's original window value for this particular user
# Provide a None to "max_requests" or "window" in order to disable rate limiting (for the given
# user and endpoint).
# If a dictionary without a "username" key is provided, an AssertionError is raised.
async def get_user_with_override(headers: Headers, path: str):
# This user callable returns a dictionary and overrides max_requests for the user "admin"
# when the endpoint's URL is '/auth'.
username = headers['authorization'].replace('Bearer ', '')
result_dict = {"username": username}
if username == 'admin' and path == '/auth':
result_dict['max_requests'] = 7
return result_dict
# 3 requests max per 20 seconds, per user
@app.post("/auth",
dependencies=[Depends(rate_limiter(3, 20,
user=get_user_with_override))])
async def read_with_auth(data: dict):
return {'input': data}
Metadata
Release files for fastapi-user-limiter 1.3.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 | |
|---|---|---|---|
| fastapi_user_limiter-1.3.0.tar.gz | 5.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fastapi_user_limiter-1.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 10.5 kB
Release files / fastapi_user_limiter-1.3.0.tar.gz
| Download URL | fastapi_user_limiter-1.3.0.tar.gz |
|---|---|
| Size | 5.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
55c37e9f4c8864e0438e18a7cb24c66eddaf0333d40c0fa8df8f2375ee7cadc9
|
|
BLAKE2b-256 checksum How to use checksums |
63718c70ded6993f9b7e7c8a1fbec607e87f561215b4e1ad1bb69321564bec3d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/5.0.0 CPython/3.9.19
|
Release files / fastapi_user_limiter-1.3.0-py3-none-any.whl
| Download URL | fastapi_user_limiter-1.3.0-py3-none-any.whl |
|---|---|
| Size | 5.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f9c4bd13d6cbbafad2ceef237448f4d95dacb3f67f2b2871b6d0d04850b25e0d
|
|
BLAKE2b-256 checksum How to use checksums |
ad32e69f34b20e43dabffeb42b6a33ced60639d25244d72e1aebb90ed1b99749
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/5.0.0 CPython/3.9.19
|