FastAPI 教學 – API 文件(OpenAPI / Swagger / ReDoc)
主題:tags 設定
簡介
在使用 FastAPI 建立 RESTful API 時,最常被開發者關注的功能之一就是自動產生的 OpenAPI 文件(即 Swagger UI 與 ReDoc)。文件本身已經能夠完整描述路由、參數、回傳格式等資訊,但如果 API 數量龐大,直接呈現在同一頁面會讓使用者感到混亂,搜尋與維護成本也會大幅提升。
tags 正是為了解決這個問題而設計的。透過為每個路由加上「標籤」,我們可以在 Swagger UI 與 ReDoc 中把相關的端點分組、加上說明,讓文件看起來像一本結構化的手冊,提升可讀性與開發體驗。本文將從概念說明、實作範例、常見陷阱與最佳實踐,一路帶你掌握 tags 的使用技巧,並提供實務應用場景,幫助你在專案中快速上手。
核心概念
1. tags 與 OpenAPI 的關係
- OpenAPI 規範 中的
tags欄位是一個字串陣列,用來描述一組相關的 API。 - FastAPI 在產生 OpenAPI schema 時,會自動把路由上設定的
tags轉換為對應的分組資訊,並在 Swagger UI / ReDoc 中呈現。 - 每個路由可以同時擁有多個 tags,這讓同一端點同時屬於多個功能群組(例如「使用者」與「管理」)成為可能。
2. 為什麼要使用 tags
| 好處 | 說明 |
|---|---|
| 文件結構化 | 大型專案的 API 能夠依功能模組分頁顯示,使用者不必一次瀏覽全部端點。 |
| 搜尋便利 | Swagger UI 內建搜尋功能,配合 tags 可以快速定位相關 API。 |
| 授權管理 | 若你在文件層面做權限說明(例如只允許特定角色使用某些 tags),能更直觀。 |
| 自動化測試 | 測試腳本可以根據 tags 產生測試套件,分別驗證不同模組。 |
3. 基本語法
在 FastAPI 中,tags 是 APIRouter、app、或單一路由裝飾器的參數。例如:
@app.get("/items/{item_id}", tags=["商品管理"])
async def read_item(item_id: int):
...
若想一次設定多個 tags,只要傳入字串陣列即可:
@app.post("/users/", tags=["使用者", "管理"])
async def create_user(user: UserCreate):
...
4. 為 tags 加上說明(description)
OpenAPI 允許在 tags 定義中加入 description,讓文件更具說明性。FastAPI 提供 openapi_tags 參數讓開發者自行定義:
app = FastAPI(
title="My API",
openapi_tags=[
{
"name": "商品管理",
"description": "提供商品的 CRUD 操作"
},
{
"name": "使用者",
"description": "使用者註冊、登入與個人資料管理"
},
]
)
上述設定會讓 Swagger UI 中的「商品管理」與「使用者」分組都帶有對應說明。
程式碼範例
以下示範 5 個常見的 tags 使用情境,從最簡單的單一標籤到結合 APIRouter 與自訂說明。
範例 1:最簡單的單一 tag
from fastapi import FastAPI
app = FastAPI()
@app.get("/ping", tags=["健康檢查"])
async def ping():
"""
用於檢測服務是否存活
"""
return {"msg": "pong"}
說明:只要在
@app.get裡加上tags=["健康檢查"],Swagger UI 會自動把此端點放在「健康檢查」分組。
範例 2:多個 tags 同時使用
@app.post("/admin/users/", tags=["使用者", "管理"])
async def admin_create_user(user: dict):
"""
後端管理員新增使用者
"""
# 實作省略
return {"status": "created"}
說明:此端點同時屬於「使用者」與「管理」兩個分組,使用者在 UI 中會在兩個區塊皆看到此路由。
範例 3:使用 APIRouter 統一設定 tags
from fastapi import APIRouter
router = APIRouter(prefix="/products", tags=["商品管理"])
@router.get("/", summary="列出所有商品")
async def list_products():
return [{"id": 1, "name": "筆記本"}]
@router.get("/{product_id}", summary="取得單一商品")
async def get_product(product_id: int):
return {"id": product_id, "name": "筆記本"}
app.include_router(router)
說明:將
tags=["商品管理"]設定在APIRouter上,所有此 router 內的路由自動繼承同一標籤,減少重複程式碼。
範例 4:自訂 openapi_tags 以加入說明文字
app = FastAPI(
title="電商平台 API",
version="1.0.0",
openapi_tags=[
{
"name": "商品管理",
"description": "商品的 CRUD、庫存與價格相關操作"
},
{
"name": "訂單處理",
"description": "建立、查詢與取消訂單的 API"
},
]
)
@app.get("/orders/{order_id}", tags=["訂單處理"])
async def read_order(order_id: int):
return {"order_id": order_id, "status": "processing"}
說明:
openapi_tags中的description會顯示在 Swagger UI 的分組標題下方,讓文件更具可讀性。
範例 5:動態產生 tags(進階)
在大型專案中,可能會根據資料庫或設定檔自動生成 tags。以下示範如何在啟動時動態加入:
def get_dynamic_tags() -> list[dict]:
# 假設從資料庫或設定檔取得模組清單
modules = ["使用者", "商品管理", "訂單處理", "報表"]
return [{"name": m, "description": f"{m} 相關的 API"} for m in modules]
app = FastAPI(openapi_tags=get_dynamic_tags())
# 之後的路由照舊使用 tags
@app.get("/reports/", tags=["報表"])
async def get_reports():
return {"msg": "report list"}
說明:
openapi_tags接受一個 list of dict,可以在程式啟動時自行組合,讓文件結構與實際功能保持同步。
常見陷阱與最佳實踐
| 陷阱 | 說明 | 最佳實踐 |
|---|---|---|
忘記在 openapi_tags 中定義說明 |
UI 只會顯示標籤名稱,缺乏上下文說明。 | 為每個 tag 在 openapi_tags 中寫上簡短 description。 |
| 同一標籤拼寫不一致 | 例如「使用者」與「User」會被視為兩個不同分組。 | 統一使用 中文或英文,且保持大小寫一致。 |
| 過度細分 tags | 把每個路由都單獨設一個 tag,會讓 UI 變得雜亂。 | 只在功能層級(如「商品管理」)設定 tags,除非真的需要子分類。 |
在 APIRouter 與單一路由同時重複設定 |
可能產生重複或衝突的 tag。 | 若 router 已設定 tags,盡量在路由內不再重複,除非需要額外的副標籤。 |
忘記在 summary / description 中填寫說明 |
UI 只會顯示 endpoint path,使用者難以快速了解功能。 | 同時使用 tags、summary、description,提供完整文件。 |
小技巧
使用常數或 Enum 管理 tags:
from enum import Enum class Tag(str, Enum): USER = "使用者" PRODUCT = "商品管理" ORDER = "訂單處理"之後在路由上直接引用
Tag.USER,可以避免拼寫錯誤。在測試中驗證 tags:
def test_openapi_tags(): schema = app.openapi() assert "商品管理" in [t["name"] for t in schema["tags"]]確保文件產出確實包含預期的分組。
結合
dependencies為特定 tags 加上全局驗證:from fastapi import Depends, HTTPException, Security async def admin_check(token: str = Security(...)): if token != "admin": raise HTTPException(status_code=403, detail="Admin only") @app.get("/admin/stats", tags=["管理"], dependencies=[Depends(admin_check)]) async def admin_stats(): ...
實際應用場景
| 場景 | 為何使用 tags | 範例 |
|---|---|---|
| 電商平台 | 商品、訂單、會員、報表各自獨立,文件需分頁呈現。 | tags=["商品管理"]、tags=["訂單處理"] |
| 內部微服務 | 每個微服務提供多個資源,外部開發者只關心自己負責的模組。 | 在 API Gateway 統一設定 openapi_tags,讓每個子服務的文件自動合併。 |
| 多語系 API | 中文與英文同時提供,使用者可根據語系切換分組。 | tags=["使用者 (User)"],在 openapi_tags 中加入雙語說明。 |
| 權限管理系統 | 不同角色只能看到自己可操作的 API。 | 為「管理」與「普通」分別設定 tags,前端依角色過濾 UI。 |
| 自動化測試平台 | 測試腳本根據 tags 產生測試用例,分模組執行。 | 使用 pytest 讀取 app.openapi()["tags"] 產生測試矩陣。 |
總結
tags是 OpenAPI / Swagger / ReDoc 中用來分組 API 的關鍵屬性,能讓龐大的文件變得條理分明。- 在 FastAPI 中,只要在路由、
APIRouter或FastAPI本身加入tags(以及可選的openapi_tags說明),即可在 UI 中自動呈現分組。 - 最佳實踐 包括:統一命名、加入說明、避免過度細分、使用 Enum 或常數管理、在測試中驗證 tags 正確性。
- 實務上,無論是電商平台、微服務架構或權限系統,
tags都能協助團隊快速定位、溝通與維護 API。
掌握了 tags 的設定與運用,你的 FastAPI 專案不僅在開發階段更易管理,對外提供的 API 文件也會更專業、更友善。快把這些技巧套用到自己的專案中,讓 API 文件成為團隊溝通的最佳橋樑吧!