Skip to content

Commit a3ec579

Browse files
committed
Add Mkdocs
1 parent cb0b438 commit a3ec579

File tree

10 files changed

+1094
-0
lines changed

10 files changed

+1094
-0
lines changed

docs/api.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# API Reference
2+
3+
## Cap Class
4+
5+
::: fastapicap.Cap
6+
options:
7+
show_source: true
8+
show_signature: true
9+
show_root_heading: true
10+
11+
## **Strategies Class**
12+
::: fastapicap.RateLimiter
13+
options:
14+
show_source: true
15+
show_signature: true
16+
show_root_heading: true
17+
18+
::: fastapicap.SlidingWindowRateLimiter
19+
options:
20+
show_source: true
21+
show_signature: true
22+
show_root_heading: true
23+
24+
25+
::: fastapicap.TokenBucketRateLimiter
26+
options:
27+
show_source: true
28+
show_signature: true
29+
show_root_heading: true
30+
31+
::: fastapicap.LeakyBucketRateLimiter
32+
options:
33+
show_source: true
34+
show_signature: true
35+
show_root_heading: true
36+
37+
::: fastapicap.GCRARateLimiter
38+
options:
39+
show_source: true
40+
show_signature: true
41+
show_root_heading: true
42+
43+
::: fastapicap.SlidingWindowLogRateLimiter
44+
options:
45+
show_source: true
46+
show_signature: true
47+
show_root_heading: true

docs/index.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# 👋 Welcome to FastAPI-Cap!
2+
3+
**FastAPI-Cap** is a robust and flexible rate-limiting library designed specifically
4+
for FastAPI applications. Leveraging the power of Redis and highly optimized Lua scripts,
5+
Cap provides a suite of algorithms to effectively control traffic to your APIs,
6+
prevent abuse, and ensure stable service delivery.
7+
8+
Whether you need simple request limiting or sophisticated traffic shaping,
9+
FastAPI-Cap offers a battle-tested solution that integrates seamlessly into
10+
your existing FastAPI projects.
11+
12+
## 🌟 Why FastAPI-Cap?
13+
14+
* **Diverse Algorithms:** Choose from a range of algorithms to perfectly match your
15+
rate-limiting requirements.
16+
* **High Performance:** Built on Redis and efficient Lua scripting for atomic
17+
operations and minimal overhead.
18+
* **Easy Integration:** Designed as FastAPI dependencies/decorators for a smooth
19+
developer experience.
20+
* **Customizable:** Tailor key extraction and rate-limit handling to fit your
21+
application's unique needs.
22+
* **Reliable:** Distributed by nature, ensuring consistent limits across multiple
23+
API instances.
24+
25+
## ⚖️ Algorithm Comparison
26+
27+
FastAPI-Cap offers several distinct rate-limiting strategies. Each algorithm has
28+
its strengths, making it suitable for different use cases. All of these implementations
29+
leverage **Redis for state management** and **Lua scripting for atomic, high-performance
30+
operations**.
31+
32+
| Algorithm | Description | Best For | Pros | Cons |
33+
| :---------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
34+
| **Fixed Window** | Divides time into discrete, fixed windows (e.g., 60 seconds). Requests are counted within the current window, resetting when a new window begins. | Simple, aggressive limits; easy to understand. | Easy to implement; low memory footprint. | Can lead to "bursts" at the window boundary if many requests arrive simultaneously right before/after reset. |
35+
| **Token Bucket** | Tokens are added to a "bucket" at a constant rate up to a max capacity. Each request consumes one token. Allows for bursts up to bucket capacity, then enforces average rate. | Controlling average rate with allowed bursts; smooth traffic flow. | Handles bursts well; offers flexibility with capacity; good average throughput. | Can allow more requests in short bursts than the average rate if the bucket is full; configuration requires tuning capacity vs. refill rate. |
36+
| **Leaky Bucket** | Requests are placed into a "bucket" that has a fixed outflow (leak) rate. If the bucket overflows, new requests are rejected. | Ensuring a truly smooth, constant output rate; queueing requests (conceptually). | Produces the most consistent output rate; effectively smooths out bursty traffic. | Does not directly support bursts (they are absorbed and smoothed); may introduce latency if requests are conceptually queued; configuration can be unintuitive. |
37+
| **Generic Cell Rate Algorithm (GCRA)** | An advanced, precise algorithm that determines a "Theoretical Arrival Time" (TAT) for each request. It's similar to Token Bucket but often more precise for burst allowance. | Precise burst control; very smooth and fair distribution over time. | Highly accurate; excellent for preventing starvation; good for per-user limits. | Can be complex to understand and configure initially; `retry-after` calculation is based on TAT. |
38+
| **Approximated Sliding Window** | Uses two fixed windows (current and previous) and a weighted average to estimate the count in a sliding window. More efficient than log-based, smoother than fixed. | Balancing accuracy and resource usage. | Better burst handling than fixed window; more memory-efficient than log-based sliding window. | Not perfectly accurate (it's an approximation); still susceptible to some boundary issues if not carefully tuned. |
39+
| **Sliding Window (Log-based)** | Records a timestamp for every request in a sorted set. The count is dynamically calculated by removing old timestamps and summing the remaining within the window. | Highest accuracy and fairness; eliminates fixed window "burst" problem. | Most accurate and fair; ensures consistent rate over any time slice within the window. | Can be more memory-intensive for high request volumes due to storing individual timestamps. |
40+
41+
## 🚀 Get Started
42+
43+
Ready to implement robust rate limiting in your FastAPI application?
44+
45+
[**➡️ Jump to the Quickstart Guide**](quickstart.md)
46+
47+
Or [explore each algorithm](strategies/overview.md) in detail:

docs/quickstart.md

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
# FastAPI Cap Quick Start
2+
3+
**FastAPI Cap** is a robust, extensible rate limiting library for FastAPI, powered by Redis. This guide will help you get started quickly with the Fixed Window rate limiting strategy.
4+
5+
---
6+
7+
## 1. Installation
8+
9+
Install the package using pip:
10+
11+
```bash
12+
pip install fastapicap
13+
```
14+
15+
**Note**: You also need a running Redis instance. You can run one locally using Docker:
16+
17+
18+
---
19+
20+
## 2. Initialize the App
21+
22+
Before using any limiter, you must initialize the shared Redis connection.
23+
You can do this in your FastAPI app's lifespan event or directly at startup.
24+
25+
```python
26+
from fastapi import FastAPI
27+
from fastapicap import Cap
28+
29+
app = FastAPI()
30+
Cap.init_app("redis://localhost:6379/0")
31+
32+
```
33+
34+
---
35+
36+
## 3. Using the Fixed Window Rate Limiter
37+
38+
Import the `RateLimiter` (Also Known As Fixed Window Rate Limiter) and use it as a dependency on your route:
39+
40+
```python
41+
from fastapi import Depends
42+
limiter1 = RateLimiter(limit=5, minutes=1)
43+
44+
@app.get("/limited", dependencies=[Depends(limiter1)])
45+
async def limited_endpoint():
46+
return {"message": "You are within the rate limit!"}
47+
```
48+
49+
If the limit is exceeded, the client receives a `429 Too Many Requests` response with a `Retry-After` header.
50+
51+
---
52+
53+
## 4. Using Multiple Limiters on a Single Route
54+
55+
You can combine multiple limiters for more granular control.
56+
For example, to allow **1 request per second** and **30 requests per minute**:
57+
58+
```python
59+
from fastapi import FastAPI, Depends
60+
from fastapicap import Cap, RateLimiter
61+
62+
## App Init part
63+
64+
limiter_1s = RateLimiter(limit=1, seconds=1)
65+
limiter_30m = RateLimiter(limit=30, minutes=1)
66+
67+
@app.get("/strict", dependencies=[Depends(limiter_1s), Depends(limiter_30m)])
68+
async def strict_endpoint():
69+
return {"message": "You passed both rate limits!"}
70+
```
71+
72+
If either limit is exceeded, the request will be blocked.
73+
74+
---
75+
76+
### **Notes**
77+
78+
- The default key for rate limiting is based on the client IP and request path.
79+
- All limiters are backed by Redis and require a working Redis connection.
80+
- Only dependency-based usage is currently supported and tested.
81+
82+
---
83+
84+
## 5. Customizing `on_limit` and `key_func` in FastAPI Cap
85+
FastAPI Cap allows you to customize how rate limits are enforced and how unique clients are identified by providing your own `on_limit` and `key_func` functions to any limiter.
86+
This guide explains how to use and implement custom `on_limit` and `key_func` functions, including the parameters they receive.
87+
88+
89+
### Default `key_func` Implementation
90+
91+
By default, FastAPI Cap uses the client IP address and request path to generate a unique key for each client and endpoint.
92+
93+
```python
94+
@staticmethod
95+
async def _default_key_func(request: Request) -> str:
96+
"""
97+
Default key function: uses client IP and request path.
98+
"""
99+
x_forwarded_for = request.headers.get("X-Forwarded-For")
100+
if x_forwarded_for:
101+
client_ip = x_forwarded_for.split(",")[0].strip()
102+
else:
103+
client_ip = request.client.host if request.client else "unknown"
104+
return f"{client_ip}:{request.url.path}"
105+
```
106+
- **Parameters:**
107+
- `request`: The FastAPI `Request` object.
108+
- **Returns:**
109+
- A string key in the format `client_ip:/path`.
110+
111+
### Default `on_limit` Implementation
112+
113+
By default, FastAPI Cap raises a `429 Too Many Requests` HTTPException and sets the `Retry-After` header.
114+
115+
```python
116+
@staticmethod
117+
async def _default_on_limit(request, response, retry_after: int) -> None:
118+
"""
119+
Default handler when the rate limit is exceeded.
120+
"""
121+
from fastapi import HTTPException
122+
123+
raise HTTPException(
124+
status_code=429,
125+
detail="Rate limit exceeded. Please try again later.",
126+
headers={"Retry-After": str(retry_after)},
127+
)
128+
```
129+
130+
- **Parameters:**
131+
- `request`: The FastAPI `Request` object.
132+
- `response`: The FastAPI `Response` object (not used in the default).
133+
- `retry_after`: An integer indicating how many seconds to wait before retrying.
134+
135+
---
136+
137+
138+
### Custom `key_func`
139+
140+
The `key_func` is responsible for generating a unique key for each client/request.
141+
You can provide your own logic to rate limit by user ID, API key, or any other identifier.
142+
143+
### **Signature**
144+
145+
```python
146+
async def key_func(request: Request) -> str:
147+
...
148+
```
149+
150+
### **Example: Rate Limit by User ID**
151+
152+
```python
153+
from fastapi import Request
154+
155+
async def user_id_key_func(request: Request) -> str:
156+
# Assume user ID is stored in request.state.user_id
157+
user_id = getattr(request.state, "user_id", None)
158+
if user_id is None:
159+
# Fallback to IP if user is not authenticated
160+
client_ip = request.client.host if request.client else "unknown"
161+
return f"anon:{client_ip}:{request.url.path}"
162+
return f"user:{user_id}:{request.url.path}"
163+
```
164+
165+
**Usage:**
166+
167+
```python
168+
limiter = RateLimiter(limit=10, minutes=1, key_func=user_id_key_func)
169+
```
170+
171+
### **Using Your Custom `on_limit` Handler**
172+
173+
The `on_limit` function is called when a client exceeds the rate limit.
174+
You can customize this to log, return a custom response, or perform other actions.
175+
176+
### Signature
177+
178+
```python
179+
async def on_limit(request: Request, response: Response, retry_after: int) -> None:
180+
...
181+
```
182+
183+
### **Example: Custom JSON Error Response**
184+
185+
```python
186+
from fastapi import Request, Response
187+
from fastapi.responses import JSONResponse
188+
189+
async def custom_on_limit(request: Request, response: Response, retry_after: int):
190+
response = JSONResponse(
191+
status_code=429,
192+
content={
193+
"error": "Too many requests",
194+
"retry_after": retry_after,
195+
"detail": "Please slow down!"
196+
},
197+
headers={"Retry-After": str(retry_after)},
198+
)
199+
raise response
200+
```
201+
202+
**Usage:**
203+
204+
```python
205+
limiter = RateLimiter(limit=5, minutes=1, on_limit=custom_on_limit)
206+
```
207+
208+
---
209+
210+
211+
## Next Steps
212+
213+
- Explore other strategies: Sliding Window, Token Bucket, Leaky Bucket, GCRA, and Sliding Window Log.
214+
215+
---
216+
217+
**Happy rate limiting!**

0 commit comments

Comments
 (0)