本文 AI 產出,尚未審核

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 中,tagsAPIRouterapp、或單一路由裝飾器的參數。例如:

@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,使用者難以快速了解功能。 同時使用 tagssummarydescription,提供完整文件。

小技巧

  1. 使用常數或 Enum 管理 tags

    from enum import Enum
    
    class Tag(str, Enum):
        USER = "使用者"
        PRODUCT = "商品管理"
        ORDER = "訂單處理"
    

    之後在路由上直接引用 Tag.USER,可以避免拼寫錯誤。

  2. 在測試中驗證 tags

    def test_openapi_tags():
        schema = app.openapi()
        assert "商品管理" in [t["name"] for t in schema["tags"]]
    

    確保文件產出確實包含預期的分組。

  3. 結合 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"] 產生測試矩陣。

總結

  • tagsOpenAPI / Swagger / ReDoc 中用來分組 API 的關鍵屬性,能讓龐大的文件變得條理分明。
  • 在 FastAPI 中,只要在路由、APIRouterFastAPI 本身加入 tags(以及可選的 openapi_tags 說明),即可在 UI 中自動呈現分組。
  • 最佳實踐 包括:統一命名、加入說明、避免過度細分、使用 Enum 或常數管理、在測試中驗證 tags 正確性。
  • 實務上,無論是電商平台、微服務架構或權限系統,tags 都能協助團隊快速定位、溝通與維護 API。

掌握了 tags 的設定與運用,你的 FastAPI 專案不僅在開發階段更易管理,對外提供的 API 文件也會更專業、更友善。快把這些技巧套用到自己的專案中,讓 API 文件成為團隊溝通的最佳橋樑吧!