Initial commit: fastapi-traffic rate limiting library

- Core rate limiting with multiple algorithms (sliding window, token bucket, etc.)
- SQLite and memory backends
- Decorator and dependency injection patterns
- Middleware support
- Example usage files
This commit is contained in:
2026-01-09 00:26:19 +00:00
commit da496746bb
38 changed files with 5790 additions and 0 deletions

View File

@@ -0,0 +1,89 @@
"""Data models for rate limiting."""
from __future__ import annotations
from dataclasses import dataclass, field
from enum import Enum
from typing import Any
class KeyType(str, Enum):
"""Type of key extraction for rate limiting."""
IP = "ip"
USER = "user"
API_KEY = "api_key"
ENDPOINT = "endpoint"
CUSTOM = "custom"
@dataclass(frozen=True, slots=True)
class RateLimitInfo:
"""Information about the current rate limit state."""
limit: int
remaining: int
reset_at: float
retry_after: float | None = None
window_size: float = 60.0
def to_headers(self) -> dict[str, str]:
"""Convert rate limit info to HTTP headers."""
headers: dict[str, str] = {
"X-RateLimit-Limit": str(self.limit),
"X-RateLimit-Remaining": str(max(0, self.remaining)),
"X-RateLimit-Reset": str(int(self.reset_at)),
}
if self.retry_after is not None:
headers["Retry-After"] = str(int(self.retry_after))
return headers
@dataclass(frozen=True, slots=True)
class RateLimitResult:
"""Result of a rate limit check."""
allowed: bool
info: RateLimitInfo
key: str
@dataclass(slots=True)
class TokenBucketState:
"""State for token bucket algorithm."""
tokens: float
last_update: float
@dataclass(slots=True)
class SlidingWindowState:
"""State for sliding window algorithm."""
timestamps: list[float] = field(default_factory=list)
count: int = 0
@dataclass(slots=True)
class FixedWindowState:
"""State for fixed window algorithm."""
count: int
window_start: float
@dataclass(slots=True)
class LeakyBucketState:
"""State for leaky bucket algorithm."""
water_level: float
last_update: float
@dataclass(frozen=True, slots=True)
class BackendRecord:
"""Generic record stored in backends."""
key: str
data: dict[str, Any]
expires_at: float