-
Notifications
You must be signed in to change notification settings - Fork 107
Open
Description
Describe the bug
I am developing a web app and want to apply rate limiting to an endpoint based on both IP and email at the same time. According to the doc, multiple limit decorator is supported but I did not find any example. I tried to develop my code based on some given examples, but it doesn’t work.
To Reproduce
from fastapi import FastAPI, Request
from pydantic import BaseModel, EmailStr
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
import json
# Custom key function to get email from request body
def get_email_key(request: Request):
"""Extract email from request body for rate limiting."""
try:
if hasattr(request.state, 'body'):
body_str = request.state.body.decode('utf-8')
data = json.loads(body_str)
email = data.get('email', 'anonymous')
return email
return 'anonymous'
except Exception as e:
return 'anonymous'
# Initialize rate limiters
limiter = Limiter(key_func=get_remote_address) # IP-based limiter
email_limiter = Limiter(key_func=get_email_key) # Email-based limiter
# Create FastAPI app
app = FastAPI(title="Registration Server with Rate Limiting")
# Add rate limiters to app state
app.state.limiter = limiter
app.state.email_limiter = email_limiter
# Add exception handler for rate limit exceeded
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
class RegisterRequest(BaseModel):
email: EmailStr
password: str
ip: str
@app.post("/register")
@limiter.limit("5/minute") # Allow 5 requests per minute per IP
@email_limiter.limit("3/minute") # Allow 3 requests per minute per email
async def register(request: Request, data: RegisterRequest):
"""
Register endpoint with rate limiting based on both IP address and email.
Rate limits:
- 5 requests per minute per IP
- 3 requests per minute per email
Args:
email: User email address
password: User password
ip: User IP address
Returns:
Success message with registration details
"""
# Here you would typically:
# 1. Validate the password strength
# 2. Hash the password
# 3. Store user in database
# 4. Send verification email
return {
"status": "success",
"message": "User registered successfully",
"data": {
"email": data.email,
"ip": data.ip
}
}
@app.get("/")
async def root():
"""Root endpoint to verify server is running."""
return {
"message": "Registration server is running",
"endpoints": {
"register": "/register (POST)",
"rate_limits": {
"ip": "5 requests per minute per IP",
"email": "3 requests per minute per email"
}
}
}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
The above is a simple demo generated by AI. I found that only the first limiter works while the email limiter does not.
Expected behavior
Both limiter works.
Screenshots
If applicable, add screenshots to help explain your problem.
Your app (please complete the following information):
- fastapi
- V0.128.0
- slowapi version: 0.1.9 (the latest version)
Additional context
Add any other context about the problem here.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels