Quickstart ========== Let's get rate limiting working in your FastAPI app. This guide covers the basics — you'll have something running in under five minutes. Your First Rate Limit --------------------- The simplest way to add rate limiting is with the ``@rate_limit`` decorator: .. code-block:: python from fastapi import FastAPI, Request from fastapi_traffic import rate_limit app = FastAPI() @app.get("/api/hello") @rate_limit(10, 60) # 10 requests per 60 seconds async def hello(request: Request): return {"message": "Hello, World!"} That's the whole thing. Let's break down what's happening: 1. The decorator takes two arguments: ``limit`` (max requests) and ``window_size`` (in seconds) 2. Each client is identified by their IP address by default 3. When a client exceeds the limit, they get a 429 response with a ``Retry-After`` header .. note:: The ``request: Request`` parameter is required. FastAPI Traffic needs access to the request to identify the client and track their usage. Testing It Out -------------- Fire up your app and hit the endpoint a few times: .. code-block:: bash # Start your app uvicorn main:app --reload # In another terminal, make some requests curl -i http://localhost:8000/api/hello You'll see headers like these in the response: .. code-block:: http HTTP/1.1 200 OK X-RateLimit-Limit: 10 X-RateLimit-Remaining: 9 X-RateLimit-Reset: 1709834400 After 10 requests, you'll get: .. code-block:: http HTTP/1.1 429 Too Many Requests Retry-After: 45 X-RateLimit-Limit: 10 X-RateLimit-Remaining: 0 Choosing an Algorithm --------------------- Different situations call for different rate limiting strategies. Here's a quick guide: .. code-block:: python from fastapi_traffic import rate_limit, Algorithm # Token Bucket - great for APIs that need burst handling # Allows short bursts of traffic, then smooths out @app.get("/api/burst-friendly") @rate_limit(100, 60, algorithm=Algorithm.TOKEN_BUCKET, burst_size=20) async def burst_endpoint(request: Request): return {"status": "ok"} # Sliding Window - most accurate, but uses more memory # Perfect when you need precise rate limiting @app.get("/api/precise") @rate_limit(100, 60, algorithm=Algorithm.SLIDING_WINDOW) async def precise_endpoint(request: Request): return {"status": "ok"} # Fixed Window - simple and efficient # Good for most use cases, slight edge case at window boundaries @app.get("/api/simple") @rate_limit(100, 60, algorithm=Algorithm.FIXED_WINDOW) async def simple_endpoint(request: Request): return {"status": "ok"} See :doc:`/user-guide/algorithms` for a deep dive into each algorithm. Rate Limiting by API Key ------------------------ IP-based limiting is fine for public endpoints, but for authenticated APIs you probably want to limit by API key: .. code-block:: python def get_api_key(request: Request) -> str: """Extract API key from header, fall back to IP.""" api_key = request.headers.get("X-API-Key") if api_key: return f"key:{api_key}" # Fall back to IP for unauthenticated requests return request.client.host if request.client else "unknown" @app.get("/api/data") @rate_limit(1000, 3600, key_extractor=get_api_key) # 1000/hour per API key async def get_data(request: Request): return {"data": "sensitive stuff"} Global Rate Limiting with Middleware ------------------------------------ Sometimes you want a blanket rate limit across your entire API. That's what middleware is for: .. code-block:: python from fastapi_traffic.middleware import RateLimitMiddleware app = FastAPI() app.add_middleware( RateLimitMiddleware, limit=1000, window_size=60, exempt_paths={"/health", "/docs", "/openapi.json"}, ) # All endpoints now have a shared 1000 req/min limit @app.get("/api/users") async def get_users(): return {"users": []} @app.get("/api/posts") async def get_posts(): return {"posts": []} Using a Persistent Backend -------------------------- The default memory backend works great for development, but it doesn't survive restarts and doesn't work across multiple processes. For production, use SQLite or Redis: **SQLite** — Good for single-node deployments: .. code-block:: python from fastapi_traffic import RateLimiter, SQLiteBackend from fastapi_traffic.core.limiter import set_limiter # Set up persistent storage backend = SQLiteBackend("rate_limits.db") limiter = RateLimiter(backend) set_limiter(limiter) @app.on_event("startup") async def startup(): await limiter.initialize() @app.on_event("shutdown") async def shutdown(): await limiter.close() **Redis** — Required for distributed systems: .. code-block:: python from fastapi_traffic import RateLimiter from fastapi_traffic.backends.redis import RedisBackend from fastapi_traffic.core.limiter import set_limiter @app.on_event("startup") async def startup(): backend = await RedisBackend.from_url("redis://localhost:6379/0") limiter = RateLimiter(backend) set_limiter(limiter) await limiter.initialize() Handling Rate Limit Errors -------------------------- By default, exceeding the rate limit raises a ``RateLimitExceeded`` exception that returns a 429 response. You can customize this: .. code-block:: python from fastapi import Request from fastapi.responses import JSONResponse from fastapi_traffic import RateLimitExceeded @app.exception_handler(RateLimitExceeded) async def rate_limit_handler(request: Request, exc: RateLimitExceeded): return JSONResponse( status_code=429, content={ "error": "slow_down", "message": "You're making too many requests. Take a breather.", "retry_after": exc.retry_after, }, ) What's Next? ------------ You've got the basics down. Here's where to go from here: - :doc:`/user-guide/algorithms` — Understand when to use each algorithm - :doc:`/user-guide/backends` — Learn about storage options - :doc:`/user-guide/key-extractors` — Advanced client identification - :doc:`/user-guide/configuration` — Load settings from files and environment variables