Decorator API
Relevant source files
The following files were used as context for generating this wiki page:
The Decorator API in FastLimit provides a declarative and high-level interface for applying rate limiting to Python functions, primarily targeted at FastAPI endpoints and other asynchronous frameworks. It abstracts the complexity of manual rate limit checking, key extraction, and metadata storage, allowing developers to secure endpoints using simple Python decorators.
The API is designed to be "async-first," although it includes logic to wrap synchronous functions into asynchronous wrappers to ensure compatibility with the core RateLimiter's async backend operations. Beyond simple rate limiting, the Decorator API supports advanced features such as dynamic key extraction, multi-tenant tiering, and variable request costs based on the incoming request object.
Sources: fastlimit/decorators.py:1-40, README.md:120-135, fastlimit/limiter.py:20-40
Core Component: @limiter.limit
The primary entry point for the Decorator API is the limit method within the RateLimiter class. This method acts as a factory that returns a decorator configured with specific rate limiting parameters.
Parameters and Configuration
| Parameter | Type | Description |
|---|---|---|
rate | str | The rate limit string (e.g., "100/minute", "10/second"). |
key | Callable | Optional function to extract the rate limit key from the Request object. |
tenant_type | Callable | Optional function to determine the tenant tier (e.g., "free", "premium"). |
algorithm | str | Specific algorithm to override the default (fixed_window, token_bucket, etc.). |
cost | Callable | Optional function to calculate the numeric cost of a specific request. |
trust_proxy_headers | bool | If True, trusts X-Forwarded-For for IP extraction. Defaults to False. |
Sources: fastlimit/limiter.py:210-245, fastlimit/decorators.py:30-55
Execution Logic
When a decorated function is called, the Decorator API performs several automated steps:
- Request Extraction: Locates the
Requestobject within the function arguments. - Key Resolution: Executes the provided
key_funcor falls back to the default IP-based key. - Rate Check: Calls the
RateLimiter.check_with_info()method to perform the atomic Redis operation. - State Management: If the check passes, usage information is stored in the request's
statefor middleware access. If it fails, aRateLimitExceededexception is raised with the necessary headers.
The following diagram illustrates the flow of a request through the Decorator API:
This flow ensures that rate limit checks happen before any application logic is executed.
Sources: fastlimit/decorators.py:70-150, tests/test_decorators.py:20-40
Key and Tenant Extraction
The Decorator API relies on Callable types to dynamically resolve identifying information from the request context.
Default Key Extraction
If no key function is provided, the API uses _get_default_key. It attempts to retrieve the client host from the request.client attribute. If trust_proxy_headers is enabled, it will check X-Forwarded-For (taking the first IP in the chain) or X-Real-IP.
Sources: fastlimit/decorators.py:180-215
Dynamic Cost and Multi-Tenancy
Developers can pass functions to the cost and tenant_type parameters to implement complex logic:
- Cost Function: Allows expensive operations (like AI inference) to count as multiple "hits" against the quota.
- Tenant Function: Allows the system to look up the user's tier and apply different limits based on that tier within the same endpoint.
@limiter.limit(
rate="100/minute",
cost=lambda req: 5 if req.url.path.endswith("/export") else 1,
tenant_type=lambda req: req.headers.get("X-Tenant-Tier", "free")
)
async def dynamic_endpoint(request: Request):
return {"status": "ok"}
Sources: fastlimit/decorators.py:160-175, examples/fastapi_app.py:130-150, tests/test_decorators.py:80-110
Integration with Request State
A critical feature of the Decorator API is its integration with the request.state object. This enables communication between the decorator and the RateLimitHeadersMiddleware.
Rate Limit Info Storage
When a check is successful, the _check_rate_limit internal function populates request.state.rate_limit_info. This dictionary contains:
limit: The maximum allowed requests.remaining: The remaining requests in the window.window_seconds: The duration of the window.ttl: The time until the window resets.
Error Headers
If a RateLimitExceeded exception is raised, the decorator attaches a rate_limit_headers dictionary to request.state. This allows the application's error handling layer to return standard headers like Retry-After and X-RateLimit-Reset even when the request fails.
Sources: fastlimit/decorators.py:145-165, fastlimit/middleware.py:80-110, tests/test_decorators.py:165-185
Middleware as a Global Decorator
The Decorator API includes a RateLimitMiddleware class which effectively acts as a global decorator for an entire ASGI application.
The middleware extracts a SimpleRequest object from the ASGI scope to identify the client IP and path before calling the limiter.
Sources: fastlimit/decorators.py:230-290, fastlimit/middleware.py:40-65
Usage Summary
The Decorator API simplifies the implementation of various rate limiting strategies as summarized below:
| Use Case | Implementation Method | Source |
|---|---|---|
| Basic IP Limiting | @limiter.limit("10/minute") | tests/test_decorators.py:20 |
| Per-User Limiting | key=lambda req: req.path_params.get("user_id") | examples/fastapi_app.py:105 |
| Weighted Operations | cost=lambda req: 10 if req.method == "POST" else 1 | fastlimit/decorators.py:170 |
| Multi-Tenant Tiers | tenant_type=lambda req: req.state.user.tier | examples/multi_tenant.py:135 |
| Global Enforcement | app.add_middleware(RateLimitMiddleware, ...) | fastlimit/decorators.py:240 |
The Decorator API represents the primary developer interface for FastLimit, bridging the gap between raw Redis-backed algorithms and high-level application frameworks like FastAPI and Starlette. By automating key extraction and state management, it ensures consistent rate limiting behavior across distributed environments with minimal code overhead.