FastAPI 路由(Routing)‧ tags 標籤完整教學
簡介
在 FastAPI 中,路由(endpoint)不只是單純的 URL 與處理函式,還可以透過 tags 為 API 做分組、說明與文件化。tags 直接影響自動產生的 OpenAPI(Swagger)文件,讓前端、測試或第三方開發者在瀏覽 API 文件時,一眼就能看出功能模組的歸屬與邏輯結構。
對於從 小型原型 到 企業級服務 的開發者而言,善用 tags 能夠:
- 提升文件可讀性:同類型的路由會被聚合在一起,減少翻找時間。
- 方便權限管理:在結合 API Gateway 或 RBAC 時,可依
tag快速套用授權規則。 - 支援自動化測試:測試框架可以根據
tag把測試案例分類,執行特定模組的回歸測試。
本篇文章將從概念說明、實作範例、常見陷阱到最佳實踐,完整帶你掌握 tags 在 FastAPI 中的使用方式。
核心概念
1. tags 的基本語法
在 FastAPI 中,每個路由裝飾器(@app.get()、@app.post()…)都接受 tags 參數,傳入 字串列表 即可。例如:
from fastapi import FastAPI
app = FastAPI()
@app.get("/users", tags=["User Management"])
async def list_users():
"""取得所有使用者資料"""
return [{"id": 1, "name": "Alice"}]
tags必須是list[str],若只傳單一字串會被視為字元迭代,導致錯誤。- OpenAPI 文件 會在
paths區塊的每個 endpoint 下自動加入tags欄位,Swagger UI 會依此分組顯示。
2. 多個 tags 同時使用
同一個路由可以同時屬於多個分組,這在 跨模組功能 時非常實用:
@app.post("/login", tags=["Authentication", "User Management"])
async def login(username: str, password: str):
"""使用者登入"""
# 驗證邏輯...
return {"token": "jwt-token"}
此例中,/login 會同時出現在「Authentication」與「User Management」兩個分組裡,方便不同角色的開發者快速定位。
3. 全域設定 tags
若整個應用程式的路由都屬於同一類別,或想為 router(子路由)統一設定 tags,可以在 APIRouter 建立時傳入 tags 參數:
from fastapi import APIRouter
router = APIRouter(
prefix="/items",
tags=["Item Operations"] # 這裡的 tags 會自動套用到所有 router 內的路由
)
@router.get("/")
async def get_items():
"""取得全部商品"""
return [{"id": 1, "name": "Notebook"}]
@router.post("/")
async def create_item(item: dict):
"""新增商品"""
return {"id": 2, **item}
在主程式中只需要 app.include_router(router),所有路由都會被歸入「Item Operations」分組。
4. tags 與 description、summary 的配合
summary:在 Swagger UI 的列表中顯示的簡短說明。description:在點擊 API 後顯示的詳細說明(支援 Markdown)。
配合 tags 使用,可讓文件更具層次感:
@app.delete("/items/{item_id}",
tags=["Item Operations"],
summary="刪除商品",
description="""
### 功能說明
- 依據 `item_id` 刪除指定商品
- 若商品不存在,回傳 **404 Not Found**
""")
async def delete_item(item_id: int):
"""刪除單一商品"""
# 刪除邏輯...
return {"detail": "Item deleted"}
5. 自訂 tags 排序與說明
FastAPI 允許在 FastAPI 初始化時傳入 openapi_tags,自訂每個 tag 的 排序、說明 以及 外部文件(如 externalDocs):
app = FastAPI(
openapi_tags=[
{
"name": "User Management",
"description": "與使用者相關的 CRUD 操作",
"externalDocs": {"description": "官方文件", "url": "https://fastapi.tiangolo.com/"}
},
{
"name": "Item Operations",
"description": "商品的新增、查詢、修改與刪除"
},
]
)
openapi_tags 中的順序會直接決定 Swagger UI 中分組的顯示順序,且每個 name 必須與路由中使用的 tags 完全相符。
程式碼範例
以下提供 5 個實用範例,從最簡單到較進階的情境,說明 tags 的多種用法。
範例 1:單一路由加 tags
# file: main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/ping", tags=["Health Check"])
async def ping():
"""簡易健康檢測端點"""
return {"message": "pong"}
說明:
tags=["Health Check"]讓此端點在 Swagger UI 中被歸入「Health Check」分組,方便運維快速定位健康檢測相關 API。
範例 2:多 tags 與 summary
@app.post("/register",
tags=["Authentication", "User Management"],
summary="使用者註冊")
async def register(username: str, password: str):
"""建立新使用者帳號"""
# 註冊邏輯...
return {"msg": "User created"}
說明:此端點同時屬於「Authentication」與「User Management」兩個分組,且在列表中只顯示
summary文字「使用者註冊」。
範例 3:使用 APIRouter 統一設定 tags
# file: routers/item.py
from fastapi import APIRouter
router = APIRouter(
prefix="/items",
tags=["Item Operations"] # 直接套用到所有子路由
)
@router.get("/", summary="取得所有商品")
async def read_items():
return [{"id": 1, "name": "筆記本"}]
@router.post("/", summary="新增商品")
async def create_item(name: str):
return {"id": 2, "name": name}
# file: main.py
from fastapi import FastAPI
from routers.item import router as item_router
app = FastAPI()
app.include_router(item_router)
說明:
router的tags只寫一次,即可讓 所有/items相關路由自動分組,減少重複程式。
範例 4:自訂 openapi_tags 排序與說明
app = FastAPI(
title="Demo API",
openapi_tags=[
{"name": "Authentication", "description": "登入、註冊相關操作"},
{"name": "User Management", "description": "使用者資料 CRUD"},
{"name": "Item Operations", "description": "商品管理"},
],
)
@app.get("/users/me", tags=["User Management"])
async def read_current_user():
"""取得目前登入者資訊"""
return {"username": "alice"}
說明:即使路由先後順序不同,Swagger UI 仍會依
openapi_tags的順序顯示分組,提升文件可讀性。
範例 5:結合 tags 與自訂 description(支援 Markdown)
@app.put("/items/{item_id}",
tags=["Item Operations"],
summary="更新商品",
description="""
**功能說明**
- 只能更新 `name` 與 `price` 欄位
- 若商品不存在回傳 `404`
**參數說明**
- `item_id`:商品唯一識別碼
- `payload`:JSON 物件,範例:
```json
{
"name": "新商品名稱",
"price": 1999
}
```
""")
async def update_item(item_id: int, payload: dict):
"""更新指定商品的資訊"""
# 更新邏輯...
return {"id": item_id, **payload}
說明:在 Swagger UI 點擊此端點時,會顯示完整的 Markdown 格式說明,讓開發者快速了解使用方式與注意事項。
常見陷阱與最佳實踐
| 常見問題 | 為什麼會發生 | 解決方案或最佳實踐 |
|---|---|---|
tags 寫成字串 (tags="User" ) |
FastAPI 期望 list[str],字串會被視為字元迭代,導致文件產生錯誤。 |
一定使用列表:tags=["User"]。 |
不同路由使用相同 tag 但未在 openapi_tags 定義說明 |
Swagger UI 仍會顯示分組,但缺少說明文字,文件看起來不完整。 | 在 FastAPI(..., openapi_tags=[]) 中為每個 tag 加上 description。 |
tags 名稱拼寫不一致 ("User" vs "user") |
OpenAPI 視為不同的分組,導致同類路由被切割。 | 統一大小寫與空格,建議使用 PascalCase 或 Title Case。 |
過度使用多重 tags |
雖然可以同時屬於多個分組,但過多會讓文件變得雜亂,失去分組意義。 | 只在跨模組且必要的情況下加第二個 tag,保持每個分組的聚焦度。 |
未為路由提供 summary |
在 Swagger UI 的列表中只能看到長長的路徑,降低可讀性。 | 為每個路由加上 summary(簡短描述)與 description(詳細說明)。 |
最佳實踐清單
- 統一命名規則:如「User Management」、 「Item Operations」等,保持大小寫與空格一致。
- 在
FastAPI初始化時設定openapi_tags,提供說明與排序。 - 每個路由至少提供
summary,讓列表更易掃描。 - 適度使用多重
tags:僅在真的跨模組時才加第二個。 - 利用 Markdown 撰寫
description,提升文件可讀性與可維護性。
實際應用場景
大型微服務平台
- 每個微服務提供多個功能模組(認證、商品、訂單)。使用
tags把同一服務的 API 按模組分組,前端開發者可一次只關注「訂單」相關端點,減少噪音。
- 每個微服務提供多個功能模組(認證、商品、訂單)。使用
API Gateway + RBAC
- 在 API Gateway 中,可根據
tag直接套用授權政策(例如只允許 Admin 存取「User Management」)。這樣的規則比單獨寫每條路徑的 ACL 更易維護。
- 在 API Gateway 中,可根據
自動化測試
- 測試框架(如
pytest)可根據tag產生測試套件,執行「Health Check」或「Authentication」相關的測試,快速驗證關鍵功能。
- 測試框架(如
文件產出與客製化
- 企業內部可能需要將 OpenAPI 文件匯出成 PDF。透過
openapi_tags的description,可以在 PDF 中自動產生章節說明,提升文件的專業度。
- 企業內部可能需要將 OpenAPI 文件匯出成 PDF。透過
總結
tags是 FastAPI 為 API 文件化、分組管理、權限控制 提供的核心機制。- 只要在路由裝飾器或
APIRouter中加入tags=["Your Tag"],就能在 Swagger UI 中自動產生清晰的分組。 - 配合
openapi_tags、summary、description(支援 Markdown)可以讓文件更完整、易讀,且有助於 跨團隊協作。 - 注意避免拼寫不一致、過度使用多重
tags,以及忘記提供summary,這些常見陷阱會降低文件品質。
掌握 tags 後,你的 FastAPI 專案不僅在 開發階段 更易維護,在 交付給前端或第三方 時也能呈現出專業且結構化的 API 文件。快把本文的範例套用到自己的專案中,體驗從雜亂無章到條理分明的改變吧!