Skip to content

Multiple limit decorators on single endpoint do not work #258

@broken-dream

Description

@broken-dream

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions