Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions changelog.d/298.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
**`add_routes()` requires `dependencies`, and content previews are off by
default.** The monitoring routes have no authentication of their own, so
`dependencies` is now a required keyword-only argument: pass your guard, or
`dependencies=[]` to mount the routes unguarded on purpose. Leaving it out, or
passing `None`, raises `TypeError`. `include_content_preview` is keyword-only
and defaults to `False`, also for apps that already pass a guard; pass `True`
to keep the first 100 bytes of each cached body in `/cached-records`. See the
[migration guide](https://fastapi-cachex.readthedocs.io/en/stable/MIGRATING_0_4/#add-routes).
27 changes: 11 additions & 16 deletions docs/HTTP_CACHING.md
Original file line number Diff line number Diff line change
Expand Up @@ -754,8 +754,8 @@ add_routes(
app,
prefix="/admin/cache", # default "" -> /cached-hits, /cached-records
include_in_schema=False, # default: hidden from OpenAPI
dependencies=[Depends(verify_admin)],
include_content_preview=False, # default True: show the first 100 bytes
dependencies=[Depends(verify_admin)], # required, keyword-only
include_content_preview=True, # default False: no body previews
)
```

Expand All @@ -764,10 +764,10 @@ add_routes(
expiry, plus counts of valid and expired entries
and the distinct cached paths. It does not count hits.
- `GET {prefix}/cached-records` — every cached record with its size, expiry,
`media_type` (the stored response's media type, `null` if it had none) and a
preview of the first 100 bytes of the cached content. With
`include_content_preview=False`, `content_preview` is `null` and no response
body leaves the server; keys, sizes and expiry are still reported.
`media_type` (the stored response's media type, `null` if it had none) and,
with `include_content_preview=True`, a preview of the first 100 bytes of the
cached content. By default `content_preview` is `null` and no response body
leaves the server; keys, sizes and expiry are still reported.
`content_type` is always `"bytes"` and is kept for compatibility; read
`media_type` instead.

Expand All @@ -778,16 +778,11 @@ keys from a `key_builder` that does not use `build_cache_key()`.
> [!WARNING]
> **These routes have no authentication of their own.** `include_in_schema=False`
> only hides them from the OpenAPI document; anyone who guesses the path can read
> them. `/cached-records` includes a preview of the cached content (unless
> `include_content_preview=False`) and exposes your whole route structure. In
> production always pass `dependencies=[Depends(your_auth)]`, or mount them on
> an internal-only app.
>
> Calling `add_routes()` without `dependencies` emits a `UserWarning`. Version
> 0.4.0 will require the parameter and turn `include_content_preview` off by
> default ([#298](https://github.com/allen0099/FastAPI-CacheX/issues/298)). For
> a local or test app that should stay open, pass `dependencies=[]` to opt out
> deliberately without the warning.
> them. They expose your whole route structure, including query strings, and
> with `include_content_preview=True` the start of every cached response. So
> `dependencies` is required: pass `dependencies=[Depends(your_auth)]`, or mount
> the routes on an internal-only app. For a local or test app that should stay
> open, pass `dependencies=[]` to opt out deliberately.

The runnable example guards them with a token from an environment variable, and
keeps them closed while the variable is unset:
Expand Down
4 changes: 2 additions & 2 deletions docs/MIGRATING_0_4.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Every warning below names the setting to change and links to its issue. `FutureW
| `get_or_set()` locks by default | [#280](https://github.com/allen0099/FastAPI-CacheX/issues/280) | `FutureWarning` | [get_or_set lock](#get-or-set-lock) |
| `get_session_manager` resolves through `SessionManagerProxy` | [#131](https://github.com/allen0099/FastAPI-CacheX/issues/131) | `FutureWarning` | [get_session_manager](#get-session-manager) |
| `token_source_priority` names every token source; a list without `"cookie"` disables the cookie | [#75](https://github.com/allen0099/FastAPI-CacheX/issues/75) | `FutureWarning` | [Token sources](#token-source-priority) |
| `add_routes()` requires `dependencies`, no content preview by default | [#298](https://github.com/allen0099/FastAPI-CacheX/issues/298) | `UserWarning` | [Monitoring routes](#add-routes) |
| `add_routes()` requires `dependencies`, no content preview by default | [#298](https://github.com/allen0099/FastAPI-CacheX/issues/298) | `UserWarning` (only when `dependencies` is left out) | [Monitoring routes](#add-routes) |
| Redis `encoding` option removed | [#126](https://github.com/allen0099/FastAPI-CacheX/issues/126) | `DeprecationWarning` (`RuntimeWarning` for a value other than UTF-8) | [Redis encoding](#redis-encoding) |
| JWT HMAC secrets shorter than the hash output are rejected | [#129](https://github.com/allen0099/FastAPI-CacheX/issues/129) | `UserWarning` | [JWT secret length](#jwt-secret) |
| `SessionMiddleware` removed | [#69](https://github.com/allen0099/FastAPI-CacheX/issues/69) | `DeprecationWarning` | [SessionMiddleware](#session-middleware) |
Expand Down Expand Up @@ -287,7 +287,7 @@ Redis and Memcached store the headers as a JSON list of `[name, value]` lines. 0

### Monitoring routes {#add-routes}

`add_routes()` requires `dependencies` in 0.4.0, and `include_content_preview` defaults to `False` ([#298](https://github.com/allen0099/FastAPI-CacheX/issues/298)). 0.3.9 emits a `UserWarning` when `dependencies` is left out.
`add_routes()` requires `dependencies` in 0.4.0, and `include_content_preview` defaults to `False` ([#298](https://github.com/allen0099/FastAPI-CacheX/issues/298)). 0.3.9 emits a `UserWarning` when `dependencies` is left out. `dependencies` and `include_content_preview` are keyword-only; leaving `dependencies` out, or passing `None`, raises `TypeError`. 0.3.9 did not warn about the two cases that break without it: passing these arguments by position, which now raises `TypeError`, and relying on the preview default while passing `dependencies`, which now hides the previews; pass `include_content_preview=True` to keep them.

```python
# Before
Expand Down
46 changes: 21 additions & 25 deletions fastapi_cachex/routes.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
"""Optional routes for cache monitoring and management."""

import time
import warnings
from collections.abc import Sequence
from dataclasses import dataclass
from dataclasses import field
Expand Down Expand Up @@ -235,18 +234,17 @@ def add_routes(
app: "FastAPI",
prefix: str = "",
include_in_schema: bool = False,
dependencies: Sequence[Any] | None = None,
include_content_preview: bool = True,
*,
dependencies: Sequence[Any],
include_content_preview: bool = False,
) -> None:
"""Add cache monitoring routes to the FastAPI application.

Mounts two read-only routes that report what the configured backend
currently holds. They inspect stored entries; nothing counts cache hits.
The routes have no authentication of their own, so pass ``dependencies``
in production. Leaving ``dependencies`` unset (``None``) emits a
``UserWarning``: 0.4.0 will require it. Pass ``dependencies=[]`` to mount
the routes unguarded on purpose (local or test setups) without the
warning.
The routes have no authentication of their own, so ``dependencies`` is
required: pass your guard, or ``dependencies=[]`` to mount the routes
unguarded on purpose (local or test setups).

Args:
app: FastAPI application instance
Expand All @@ -256,14 +254,15 @@ def add_routes(
Defaults to False.
dependencies: FastAPI ``Depends`` objects applied to all monitoring
routes, for authentication or authorization guards
(e.g. ``[Depends(verify_api_key)]``). ``None`` (the
default) mounts the routes unguarded and emits a
``UserWarning``; an explicit ``[]`` does the same
without the warning.
(e.g. ``[Depends(verify_api_key)]``). Required and
keyword-only; an empty list mounts the routes unguarded.
include_content_preview: Whether ``/cached-records`` includes the first
bytes of each cached response body. When False,
``content_preview`` is ``null`` while keys, sizes and
expiry are still reported. Defaults to True.
100 bytes of each cached response body. Defaults to
False, which reports ``content_preview`` as ``null``
while keys, sizes and expiry are still reported.

Raises:
TypeError: If ``dependencies`` is ``None``.

Example:
```python
Expand All @@ -277,17 +276,14 @@ def add_routes(
```
"""
if dependencies is None:
warnings.warn(
"add_routes() is mounting the cache monitoring routes without access "
"control: anyone who can reach the app can read every cached key "
"(including query strings) and previews of the cached responses. "
"Pass dependencies=[Depends(your_auth)] to guard them, or "
"dependencies=[] to opt out deliberately. Version 0.4.0 will require "
"dependencies and turn include_content_preview off by default "
"(https://github.com/allen0099/FastAPI-CacheX/issues/298).",
UserWarning,
stacklevel=2,
# Unreachable for type checkers; guards untyped callers.
msg = ( # type: ignore[unreachable]
"add_routes() requires dependencies: pass "
"dependencies=[Depends(your_auth)] to guard the cache monitoring "
"routes, or dependencies=[] to mount them unguarded on purpose "
"(https://github.com/allen0099/FastAPI-CacheX/issues/298)"
)
raise TypeError(msg)

@app.get(
f"{prefix}/cached-hits",
Expand Down
10 changes: 4 additions & 6 deletions i18n/zh-TW/docs/HTTP_CACHING.md
Original file line number Diff line number Diff line change
Expand Up @@ -447,20 +447,18 @@ add_routes(
app,
prefix="/admin/cache", # 預設 "" -> /cached-hits、/cached-records
include_in_schema=False, # 預設:不出現在 OpenAPI 中
dependencies=[Depends(verify_admin)],
include_content_preview=False, # 預設 True:顯示前 100 個位元組
dependencies=[Depends(verify_admin)], # 必填,只能以關鍵字傳入
include_content_preview=True, # 預設 False:不含本文預覽
)
```

- `GET {prefix}/cached-hits`:列出每筆快取項目,拆分為方法、主機、路徑與查詢(超過 200 位元組的查詢為 `sha256:<十六進位>`),附上 ETag 與到期時間,另外統計有效與已過期的項目數,以及不重複的快取路徑。它不會計算命中次數。
- `GET {prefix}/cached-records`:列出每筆快取紀錄的大小、到期時間、`media_type`(儲存的回應的媒體類型,沒有時為 `null`),以及快取內容前 100 個位元組的預覽。設定 `include_content_preview=False` 時,`content_preview` 為 `null`,不會有任何回應本文離開伺服器;鍵、大小與到期時間仍會回報。`content_type` 一律是 `"bytes"`,只為相容而保留;請改讀 `media_type`。
- `GET {prefix}/cached-records`:列出每筆快取紀錄的大小、到期時間、`media_type`(儲存的回應的媒體類型,沒有時為 `null`),以及在 `include_content_preview=True` 時快取內容前 100 個位元組的預覽。預設 `content_preview` 為 `null`,不會有任何回應本文離開伺服器;鍵、大小與到期時間仍會回報。`content_type` 一律是 `"bytes"`,只為相容而保留;請改讀 `media_type`。

兩個路由都只列出路由項目(格式為 `http:v2|method|host|path|query` 的鍵);`CacheManager`、Session、state 與鎖的鍵都會略過,未使用 `build_cache_key()` 的 `key_builder` 產生的鍵也一樣。

> [!WARNING]
> **這些路由本身沒有任何身分驗證。** `include_in_schema=False` 只是讓它們不出現在 OpenAPI 文件中;任何猜到路徑的人都能讀取。`/cached-records` 含有快取內容的預覽(除非設定 `include_content_preview=False`),並會暴露整個路由結構。正式環境中請務必傳入 `dependencies=[Depends(your_auth)]`,或將它們掛載在僅供內部使用的應用程式上。
>
> 呼叫 `add_routes()` 時若未傳入 `dependencies`,會發出 `UserWarning`。0.4.0 版將要求必須傳入此參數,並將 `include_content_preview` 預設改為關閉([#298](https://github.com/allen0099/FastAPI-CacheX/issues/298))。若本機或測試用的應用程式確實要保持開放,請傳入 `dependencies=[]` 明確選擇不設防護,這樣就不會出現警告。
> **這些路由本身沒有任何身分驗證。** `include_in_schema=False` 只是讓它們不出現在 OpenAPI 文件中;任何猜到路徑的人都能讀取。它們會暴露整個路由結構(包含查詢字串),設定 `include_content_preview=True` 時還會暴露每個快取回應的開頭。因此 `dependencies` 為必填:請傳入 `dependencies=[Depends(your_auth)]`,或將路由掛載在僅供內部使用的應用程式上。若本機或測試用的應用程式確實要保持開放,請傳入 `dependencies=[]` 明確選擇不設防護。

可執行範例以環境變數中的權杖保護它們,未設定該變數時路由一律拒絕存取:

Expand Down
4 changes: 2 additions & 2 deletions i18n/zh-TW/docs/MIGRATING_0_4.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ filterwarnings = [
| `get_or_set()` 預設使用鎖 | [#280](https://github.com/allen0099/FastAPI-CacheX/issues/280) | `FutureWarning` | [get_or_set 的鎖](#get-or-set-lock) |
| `get_session_manager` 透過 `SessionManagerProxy` 取得 | [#131](https://github.com/allen0099/FastAPI-CacheX/issues/131) | `FutureWarning` | [get_session_manager](#get-session-manager) |
| `token_source_priority` 列出所有權杖來源;沒有 `"cookie"` 的清單會停用 Cookie | [#75](https://github.com/allen0099/FastAPI-CacheX/issues/75) | `FutureWarning` | [權杖來源](#token-source-priority) |
| `add_routes()` 必須傳入 `dependencies`,預設不含內容預覽 | [#298](https://github.com/allen0099/FastAPI-CacheX/issues/298) | `UserWarning` | [監控路由](#add-routes) |
| `add_routes()` 必須傳入 `dependencies`,預設不含內容預覽 | [#298](https://github.com/allen0099/FastAPI-CacheX/issues/298) | `UserWarning`(僅在省略 `dependencies` 時) | [監控路由](#add-routes) |
| 移除 Redis 的 `encoding` 選項 | [#126](https://github.com/allen0099/FastAPI-CacheX/issues/126) | `DeprecationWarning`(UTF-8 以外的值為 `RuntimeWarning`) | [Redis encoding](#redis-encoding) |
| 拒絕短於雜湊輸出的 JWT HMAC 密鑰 | [#129](https://github.com/allen0099/FastAPI-CacheX/issues/129) | `UserWarning` | [JWT 密鑰長度](#jwt-secret) |
| 移除 `SessionMiddleware` | [#69](https://github.com/allen0099/FastAPI-CacheX/issues/69) | `DeprecationWarning` | [SessionMiddleware](#session-middleware) |
Expand Down Expand Up @@ -286,7 +286,7 @@ Redis 與 Memcached 以 `[name, value]` 行組成的 JSON 清單儲存標頭。0

### 監控路由 {#add-routes}

0.4.0 起 `add_routes()` 必須傳入 `dependencies`,`include_content_preview` 預設為 `False`([#298](https://github.com/allen0099/FastAPI-CacheX/issues/298))。0.3.9 在省略 `dependencies` 時會發出 `UserWarning`。
0.4.0 起 `add_routes()` 必須傳入 `dependencies`,`include_content_preview` 預設為 `False`([#298](https://github.com/allen0099/FastAPI-CacheX/issues/298))。0.3.9 在省略 `dependencies` 時會發出 `UserWarning`。`dependencies` 與 `include_content_preview` 只能以關鍵字傳入;省略 `dependencies` 或傳入 `None` 會引發 `TypeError`。0.3.9 對以下兩種情況不會發出警告:以位置傳入這些參數,現在會引發 `TypeError`;以及已傳入 `dependencies` 但依賴預覽的預設值,現在預覽會被隱藏,請傳入 `include_content_preview=True` 保留。

```python
# 修改前
Expand Down
Loading
Loading