From 60a21b887e2ca46f1cb24a67fea28f3cadf8716b Mon Sep 17 00:00:00 2001 From: Andy Stark Date: Mon, 2 Nov 2026 10:55:27 +0000 Subject: [PATCH] DOC-7232 Document fastapi-redis-sdk rate limiting, sessions, and Sentinel Add Rate limiting, Sessions, and Sentinel mode sections to the FastAPI integration page, a REDIS_SENTINEL config row, and BYPASS and vary_on_session in the caching section. The page had been written against about 0.8.0 and missed 0.8.0 rate limiting and the 0.9.0 sessions and Sentinel support. The new sections are deliberately short and link to the SDK guides for depth, as the caching section already does, because the SDK guides are still changing quickly. Snippets and behavior claims come from the SDK README and guides at 0.9.1 and were not run. The Sentinel exclusivity claim (not with REDIS_CLUSTER or REDIS_URL) is from the SDK configuration guide. FastAPIJsonCoder is left out because the guides say little about it. Learned: SDK features land faster than this page; check the SDK release list before trusting the page Rejected: full rate-limit and session option tables on this page | duplicates a fast-moving SDK guide Gaps: snippets not run against fastapi-redis-sdk 0.9.1; external guide URLs not fetched Recheck: when fastapi-redis-sdk 0.10.0 goes stable, review its release notes for page impact Ticket: DOC-7232 Co-Authored-By: Claude Sonnet 5.5 --- content/integrate/fastapi/_index.md | 99 +++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 7 deletions(-) diff --git a/content/integrate/fastapi/_index.md b/content/integrate/fastapi/_index.md index 68f861bb7c..a810a3e6bd 100644 --- a/content/integrate/fastapi/_index.md +++ b/content/integrate/fastapi/_index.md @@ -8,13 +8,14 @@ categories: - oss - rs - rc -description: Add idiomatic Redis connection management and dependency-injection caching - to FastAPI apps. +description: Add idiomatic Redis connection management, dependency-injection caching, + rate limiting, and sessions to FastAPI apps. group: framework hideListLinks: false stack: true -summary: The fastapi-redis-sdk provides automatic connection pooling and dependency-injection - caching for FastAPI, with HTTP-native ETag and Cache-Control support. +summary: The fastapi-redis-sdk provides automatic connection pooling, dependency-injection + caching with HTTP-native ETag and Cache-Control support, rate limiting, and server-side + sessions for FastAPI. type: integration weight: 9 --- @@ -27,7 +28,8 @@ lifespan and exposes caching as injectable dependencies, including HTTP-native [`ETag`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/ETag), [`304 Not Modified`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Status/304), and [`Cache-Control`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control) -support. +support. It also provides distributed [rate limiting](#rate-limiting) and +[server-side sessions](#sessions). The SDK is built on the [redis-py](/content/develop/clients/redis-py/_index.md) client, so anything redis-py can do is still available to you alongside the caching helpers. @@ -107,6 +109,7 @@ The most commonly used variables are described in the table below: | `REDIS_PASSWORD` | - | Redis password (stored securely as a Pydantic `SecretStr`) | | `REDIS_SSL` | `false` | Enable TLS (or use a `rediss://` URL) | | `REDIS_CLUSTER` | `false` | Enable [OSS Cluster mode](#cluster-mode) | +| `REDIS_SENTINEL` | `false` | Enable [Sentinel mode](#sentinel-mode) | | `REDIS_PREFIX` | `redis:fastapi` | Global prefix applied to all keys | | `REDIS_DEFAULT_TTL` | `0` | Default cache TTL in seconds (`0` = no expiry) | | `REDIS_MAX_CONNECTIONS` | - | Maximum pooled connections | @@ -162,8 +165,9 @@ async def replace_product(product_id: int, body: Product): return await db.update(product_id, body) ``` -Cached responses include an `X-Redis-Cache` header (`HIT` or `MISS`) along with -`Cache-Control` and `ETag` headers. +Cached responses include an `X-Redis-Cache` header (`HIT`, `MISS`, or `BYPASS` when the +response was served but not stored) along with `Cache-Control` and `ETag` headers. If the +response body depends on the user's session, pass `vary_on_session=True` to `cache()`. The example below drives a cached endpoint with FastAPI's [`TestClient`](https://fastapi.tiangolo.com/reference/testclient/) so you can see the @@ -206,6 +210,69 @@ the server responds with `304 Not Modified` and no body: {{< clients-example set="fastapi_tutorial" step="http_caching" lang_filter="Python" description="Use ETag and Cache-Control headers so a revalidation request returns 304 Not Modified" difficulty="intermediate" buildsUpon="cache_hit_miss" />}} +## Rate limiting + +Add `.rate_limiting()` to the builder chain, then attach the `rate_limit()` dependency +to a route. Counters live in Redis, so limits hold across every worker and pod. Stack +two limits to cap both bursts and sustained traffic. Give each a distinct `scope` so +their counters stay independent: + +```python +from fastapi import Depends, FastAPI +from redis_fastapi import FastAPIRedis, rate_limit + +app = FastAPI() +FastAPIRedis(app).lifespan().rate_limiting() + +@app.get( + "/search", + dependencies=[ + Depends(rate_limit("10/second", scope="search:burst")), + Depends(rate_limit("100/minute", scope="search:sustained")), + ], +) +async def search(): + return {"results": []} +``` + +Limits count per client IP by default. A request that exceeds either limit gets a +`429 Too Many Requests` response with a `Retry-After` header, and every response carries +`X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` headers. + +See the [SDK rate limiting guide](https://redis.github.io/fastapi-redis-sdk/guide/rate-limiting/) +for custom identifiers, an app-wide limiter, custom `429` responses, and the behavior +when Redis is unreachable. + +## Sessions + +Add `.sessions()` to the builder chain to keep session data in Redis. The cookie holds +only an opaque session ID, and Redis enforces both an idle timeout and an absolute +timeout. Inject `SessionDep` to read and write the session, and add `valid_session()` to +return `401` when a request has no live session: + +```python +from fastapi import Depends, FastAPI +from redis_fastapi import FastAPIRedis, SessionDep, valid_session + +app = FastAPI() +FastAPIRedis(app).lifespan().sessions() + +@app.post("/login") +async def login(session: SessionDep): + session["user_id"] = 42 # rotates the session ID after the endpoint completes + return {"ok": True} + +@app.get("/me", dependencies=[Depends(valid_session())]) +async def me(session: SessionDep): + return {"user_id": session.get("user_id")} +``` + +Changing the signed-in user rotates the session ID automatically. `request.session` +also works, so code written for Starlette's `SessionMiddleware` runs unchanged. See the +[SDK sessions guide](https://redis.github.io/fastapi-redis-sdk/guide/sessions/) for +timeouts, sign-out everywhere, CSRF (cross-site request forgery) protection, and +encryption. + ## Cluster mode To work with an [OSS Cluster](/content/operate/oss_and_stack/management/scaling.md), @@ -218,6 +285,24 @@ export REDIS_URL=redis://node1:6379,node2:6379,node3:6379 In cluster mode, `AsyncRedisDep` yields an `AsyncRedisCluster` client. +## Sentinel mode + +To connect through [Redis Sentinel](/content/operate/oss_and_stack/management/sentinel.md), +set `REDIS_SENTINEL=true` and list the Sentinels instead of setting `REDIS_URL`. The SDK +asks the Sentinels for the address of the current primary, and asks again after a +failover: + +```bash +export REDIS_SENTINEL=true +export REDIS_SENTINEL_NODES=sentinel1:26379,sentinel2:26379,sentinel3:26379 +export REDIS_SENTINEL_MASTER_NAME=mymaster +``` + +Your application code doesn't change. `AsyncRedisDep` yields a standard `AsyncRedis` +client connected to the current primary. Sentinel mode can't be combined with +`REDIS_CLUSTER` or `REDIS_URL`. If the Sentinels require authentication, set +`REDIS_SENTINEL_USERNAME` and `REDIS_SENTINEL_PASSWORD`. + ## Observability The SDK can emit [OpenTelemetry](https://opentelemetry.io/) spans and metrics for every