release: bump version to 0.3.0

- Refactor Redis backend connection handling and pool management
- Update algorithm implementations with improved type annotations
- Enhance config loader validation with stricter Pydantic schemas
- Improve decorator and middleware error handling
- Expand example scripts with better docstrings and usage patterns
- Add new 00_basic_usage.py example for quick start
- Reorganize examples directory structure
- Fix type annotation inconsistencies across core modules
- Update dependencies in pyproject.toml
This commit is contained in:
2026-03-17 20:55:38 +00:00
parent 492410614f
commit f3453cb0fc
51 changed files with 6507 additions and 166 deletions

245
docs/api/config.rst Normal file
View File

@@ -0,0 +1,245 @@
Configuration API
=================
Configuration classes and loaders for rate limiting.
RateLimitConfig
---------------
.. py:class:: RateLimitConfig(limit, window_size=60.0, algorithm=Algorithm.SLIDING_WINDOW_COUNTER, key_prefix="ratelimit", key_extractor=default_key_extractor, burst_size=None, include_headers=True, error_message="Rate limit exceeded", status_code=429, skip_on_error=False, cost=1, exempt_when=None, on_blocked=None)
Configuration for a rate limit rule.
:param limit: Maximum requests allowed in the window. Must be positive.
:type limit: int
:param window_size: Time window in seconds. Must be positive.
:type window_size: float
:param algorithm: Rate limiting algorithm to use.
:type algorithm: Algorithm
:param key_prefix: Prefix for the rate limit key.
:type key_prefix: str
:param key_extractor: Function to extract client identifier from request.
:type key_extractor: Callable[[Request], str]
:param burst_size: Maximum burst size for token/leaky bucket.
:type burst_size: int | None
:param include_headers: Whether to include rate limit headers.
:type include_headers: bool
:param error_message: Error message when rate limited.
:type error_message: str
:param status_code: HTTP status code when rate limited.
:type status_code: int
:param skip_on_error: Skip rate limiting on backend errors.
:type skip_on_error: bool
:param cost: Cost per request.
:type cost: int
:param exempt_when: Function to check if request is exempt.
:type exempt_when: Callable[[Request], bool] | None
:param on_blocked: Callback when request is blocked.
:type on_blocked: Callable[[Request, Any], Any] | None
**Usage:**
.. code-block:: python
from fastapi_traffic import RateLimitConfig, Algorithm
config = RateLimitConfig(
limit=100,
window_size=60,
algorithm=Algorithm.TOKEN_BUCKET,
burst_size=20,
)
GlobalConfig
------------
.. py:class:: GlobalConfig(backend=None, enabled=True, default_limit=100, default_window_size=60.0, default_algorithm=Algorithm.SLIDING_WINDOW_COUNTER, key_prefix="fastapi_traffic", include_headers=True, error_message="Rate limit exceeded. Please try again later.", status_code=429, skip_on_error=False, exempt_ips=set(), exempt_paths=set(), headers_prefix="X-RateLimit")
Global configuration for the rate limiter.
:param backend: Storage backend for rate limit data.
:type backend: Backend | None
:param enabled: Whether rate limiting is enabled.
:type enabled: bool
:param default_limit: Default maximum requests per window.
:type default_limit: int
:param default_window_size: Default time window in seconds.
:type default_window_size: float
:param default_algorithm: Default rate limiting algorithm.
:type default_algorithm: Algorithm
:param key_prefix: Global prefix for all rate limit keys.
:type key_prefix: str
:param include_headers: Include rate limit headers by default.
:type include_headers: bool
:param error_message: Default error message.
:type error_message: str
:param status_code: Default HTTP status code.
:type status_code: int
:param skip_on_error: Skip rate limiting on backend errors.
:type skip_on_error: bool
:param exempt_ips: IP addresses exempt from rate limiting.
:type exempt_ips: set[str]
:param exempt_paths: URL paths exempt from rate limiting.
:type exempt_paths: set[str]
:param headers_prefix: Prefix for rate limit headers.
:type headers_prefix: str
**Usage:**
.. code-block:: python
from fastapi_traffic import GlobalConfig, RateLimiter
config = GlobalConfig(
enabled=True,
default_limit=100,
exempt_paths={"/health", "/docs"},
exempt_ips={"127.0.0.1"},
)
limiter = RateLimiter(config=config)
ConfigLoader
------------
.. py:class:: ConfigLoader(prefix="FASTAPI_TRAFFIC")
Load rate limit configuration from various sources.
:param prefix: Environment variable prefix.
:type prefix: str
.. py:method:: load_rate_limit_config_from_env(env_vars=None, **overrides)
Load RateLimitConfig from environment variables.
:param env_vars: Dictionary of environment variables. Uses os.environ if None.
:type env_vars: dict[str, str] | None
:param overrides: Values to override after loading.
:returns: Loaded configuration.
:rtype: RateLimitConfig
.. py:method:: load_rate_limit_config_from_json(file_path, **overrides)
Load RateLimitConfig from a JSON file.
:param file_path: Path to the JSON file.
:type file_path: str | Path
:param overrides: Values to override after loading.
:returns: Loaded configuration.
:rtype: RateLimitConfig
.. py:method:: load_rate_limit_config_from_env_file(file_path, **overrides)
Load RateLimitConfig from a .env file.
:param file_path: Path to the .env file.
:type file_path: str | Path
:param overrides: Values to override after loading.
:returns: Loaded configuration.
:rtype: RateLimitConfig
.. py:method:: load_global_config_from_env(env_vars=None, **overrides)
Load GlobalConfig from environment variables.
.. py:method:: load_global_config_from_json(file_path, **overrides)
Load GlobalConfig from a JSON file.
.. py:method:: load_global_config_from_env_file(file_path, **overrides)
Load GlobalConfig from a .env file.
**Usage:**
.. code-block:: python
from fastapi_traffic import ConfigLoader
loader = ConfigLoader()
# From environment
config = loader.load_rate_limit_config_from_env()
# From JSON file
config = loader.load_rate_limit_config_from_json("config.json")
# From .env file
config = loader.load_rate_limit_config_from_env_file(".env")
# With overrides
config = loader.load_rate_limit_config_from_json(
"config.json",
limit=200, # Override the limit
)
Convenience Functions
---------------------
.. py:function:: load_rate_limit_config(file_path, **overrides)
Load RateLimitConfig with automatic format detection.
:param file_path: Path to config file (.json or .env).
:type file_path: str | Path
:returns: Loaded configuration.
:rtype: RateLimitConfig
.. py:function:: load_rate_limit_config_from_env(**overrides)
Load RateLimitConfig from environment variables.
:returns: Loaded configuration.
:rtype: RateLimitConfig
.. py:function:: load_global_config(file_path, **overrides)
Load GlobalConfig with automatic format detection.
:param file_path: Path to config file (.json or .env).
:type file_path: str | Path
:returns: Loaded configuration.
:rtype: GlobalConfig
.. py:function:: load_global_config_from_env(**overrides)
Load GlobalConfig from environment variables.
:returns: Loaded configuration.
:rtype: GlobalConfig
**Usage:**
.. code-block:: python
from fastapi_traffic import (
load_rate_limit_config,
load_rate_limit_config_from_env,
)
# Auto-detect format
config = load_rate_limit_config("config.json")
config = load_rate_limit_config(".env")
# From environment
config = load_rate_limit_config_from_env()
default_key_extractor
---------------------
.. py:function:: default_key_extractor(request)
Extract client IP as the default rate limit key.
Checks in order:
1. ``X-Forwarded-For`` header (first IP)
2. ``X-Real-IP`` header
3. Direct connection IP
4. Falls back to "unknown"
:param request: The incoming request.
:type request: Request
:returns: Client identifier string.
:rtype: str