FastAPI 資料驗證與轉換(Validation & Serialization)
主題:schema_extra 額外資訊
簡介
在使用 FastAPI 建立 API 時,我們常會依賴 Pydantic 來定義資料模型(Model),藉此完成請求參數的驗證與回傳資料的序列化。除了基本的欄位型別與驗證規則外,FastAPI 會自動根據模型產生 OpenAPI 文件,讓前端或第三方開發者能即時取得 API 規格。
然而,僅靠欄位說明與預設值,有時無法完整呈現實務上需要的範例或額外說明。這時,schema_extra 便是 Pydantic 提供的強大擴充機制,讓我們可以在模型的 JSON Schema 中加入自訂的 example、description、default 等資訊,直接影響產出的 Swagger UI 與 Redoc 文件。
掌握 schema_extra 的使用方式,不僅能讓 API 文件更具可讀性,也能在開發與除錯階段提供即時的範例,提升團隊協作效率。接下來,我們將一步步解說 schema_extra 的概念、實作方式與最佳實踐,並提供多個可直接套用的範例。
核心概念
什麼是 schema_extra?
schema_extra 是 Pydantic 模型(BaseModel)的 Config 子類別屬性之一。它接受一個字典,該字典會在模型轉換成 JSON Schema 時被合併進去。常見的用途包括:
| 用途 | 在 OpenAPI 中的呈現 |
|---|---|
| example | Swagger UI 的範例資料 |
| description | 欄位或模型的說明文字 |
| default | 預設值的顯示(不等同於模型層面的 default) |
| title | 模型或欄位的標題 |
重點:
schema_extra僅影響產生的 JSON Schema,不會改變 Pydantic 本身的驗證行為。
基本語法
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str
email: str
class Config:
# 這裡放入自訂的 JSON Schema 片段
schema_extra = {
"example": {
"id": 1,
"name": "Alice",
"email": "alice@example.com"
},
"description": "使用者資訊模型"
}
在上述程式碼中,example 會在 Swagger UI 的 Request body 或 Response model 區塊顯示,而 description 則會成為模型的說明文字。
常見的 schema_extra 結構
在模型層級加入
exampleschema_extra = { "example": { ... } }在欄位層級加入
example、descriptionschema_extra = { "properties": { "name": { "title": "使用者名稱", "description": "使用者的全名", "example": "Bob" } } }同時提供多個範例(OpenAPI 3.0+)
schema_extra = { "examples": { "basic": { "summary": "最簡單的範例", "value": {"id": 2, "name": "Carol", "email": "carol@example.com"} }, "complex": { "summary": "含有額外欄位的範例", "value": {"id": 3, "name": "Dave", "email": "dave@example.com", "age": 30} } } }
程式碼範例
以下提供 5 個實用範例,涵蓋最常見的需求與一些進階技巧。每個範例均附上說明,方便讀者快速理解。
範例 1:最基本的模型範例(單一 example)
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
is_offer: bool | None = None
class Config:
# 為整個模型提供一個範例,Swagger UI 會直接顯示
schema_extra = {
"example": {
"name": "Apple iPhone 15",
"price": 29999.0,
"is_offer": True
}
}
@app.post("/items/")
async def create_item(item: Item):
return item
說明:當使用者在 Swagger UI 點擊 Try it out 時,請求的 Body 欄位會自動填入
example中的資料,減少手動輸入的時間。
範例 2:欄位層級的說明與範例
class Product(BaseModel):
id: int
title: str
description: str | None = None
price: float
class Config:
schema_extra = {
"properties": {
"id": {
"title": "商品編號",
"description": "系統自動產生的唯一識別碼",
"example": 1001
},
"title": {
"title": "商品名稱",
"description": "顧客在前端看到的商品標題",
"example": "無線藍牙耳機"
},
"price": {
"title": "商品價格",
"description": "以新台幣為單位,含稅",
"example": 1999.5
}
}
}
說明:
properties內的每個欄位都可以自行設定title、description、example,讓文件更具可讀性。
範例 3:提供多個範例(OpenAPI 3.0+)
class Order(BaseModel):
order_id: str
items: list[Item]
total: float
class Config:
schema_extra = {
"examples": {
"single_item": {
"summary": "單一商品的訂單",
"value": {
"order_id": "ORD001",
"items": [
{"name": "USB-C 充電線", "price": 299.0, "is_offer": None}
],
"total": 299.0
}
},
"multiple_items": {
"summary": "多商品訂單",
"value": {
"order_id": "ORD002",
"items": [
{"name": "鍵盤", "price": 1200.0, "is_offer": False},
{"name": "滑鼠", "price": 650.0, "is_offer": True}
],
"total": 1850.0
}
}
}
}
說明:在 Swagger UI 中,使用者可以從 Example Value 下拉選單切換不同範例,對測試 API 的情境更靈活。
範例 4:結合 description 與 example,說明「可選欄位」的行為
class BlogPost(BaseModel):
title: str
content: str
tags: list[str] | None = None # 可選欄位
class Config:
schema_extra = {
"example": {
"title": "FastAPI 入門教學",
"content": "本文將說明如何快速上手 FastAPI...",
"tags": ["FastAPI", "Python", "Web"]
},
"properties": {
"tags": {
"description": "文章標籤,若未提供則視為無標籤",
"example": ["API", "Tutorial"]
}
}
}
說明:
tags為可選欄位,透過description說明「若未提供則視為無標籤」的行為,讓前端開發者不會誤以為此欄位是必填。
範例 5:在 response_model 中使用 schema_extra,自訂回傳範例
from fastapi import FastAPI, status
from fastapi.responses import JSONResponse
app = FastAPI()
class LoginResponse(BaseModel):
access_token: str
token_type: str = "bearer"
class Config:
schema_extra = {
"example": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer"
}
}
@app.post("/login", response_model=LoginResponse, status_code=status.HTTP_200_OK)
async def login(username: str, password: str):
# 假設驗證成功後產生 JWT
token = "dummy_jwt_token"
return JSONResponse(content={"access_token": token, "token_type": "bearer"})
說明:即使回傳是手動建立的
JSONResponse,只要在路由上指定response_model,Swagger UI 仍會顯示LoginResponse的example,協助前端了解回傳結構。
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解決方式 |
|---|---|---|
schema_extra 覆寫了自動產生的欄位資訊 |
若在 properties 中只寫了部份欄位,未列出的欄位會失去自動產生的 description、type 等資訊。 |
只在需要額外資訊的欄位上添加,其餘欄位保持空白或使用 ** 合併字典方式。 |
| 範例資料與實際驗證不一致 | example 只是一個說明,FastAPI 不會根據它進行驗證。若範例格式錯誤,文件會誤導使用者。 |
確保 example 與模型驗證規則相符(例如型別、必填欄位)。可在開發階段寫測試檢查 example 的正確性。 |
過度使用 schema_extra 造成文件臃腫 |
大量的範例或說明會讓 Swagger UI 加載變慢,且難以維護。 | 只為關鍵模型或公共 API 添加,其餘可使用全局 description 或 tags 來說明。 |
忘記在 Config 中加入 orm_mode = True |
若模型同時用於 ORM(如 SQLAlchemy)與 API 回傳,缺少 orm_mode 會導致序列化錯誤。 |
在 Config 中同時設定 orm_mode = True 與 schema_extra:class Config: orm_mode = True; schema_extra = {...} |
使用 example 時忽略 examples |
單一 example 只能提供一個範例,無法展示多種使用情境。 |
若 API 有多種輸入情境,使用 examples(OpenAPI 3.0+)提供 多個範例。 |
最佳實踐
保持範例與驗證同步
- 建議在模型檔案最上方寫下
# fmt: off,使用 IDE 快速產生example,再手動檢查。
- 建議在模型檔案最上方寫下
分層管理說明
- 模型層:使用
description、title交代整體概念。 - 欄位層:使用
properties針對每個欄位補充說明與範例。
- 模型層:使用
在專案的共用基底模型中統一設定
- 建立
BaseSchema繼承BaseModel,在其中加入orm_mode = True與通用schema_extra(如全局的example標記),子模型只需要覆寫差異部分。
- 建立
自動化測試
examplefrom pydantic import BaseModel import json def test_example_is_valid(): example = MyModel.schema()["example"] # 若 example 為 None,測試失敗 assert example is not None # 嘗試用 example 建立模型,確保驗證通過 MyModel(**example)- 這樣可避免因範例錯誤而產生的文件誤導。
實際應用場景
| 場景 | 為何需要 schema_extra |
範例 |
|---|---|---|
| 前端開發者快速測試 API | 直接在 Swagger UI 中看到完整的請求範例,減少手動組裝 JSON 的時間。 | 透過 example 或 examples 提供「登入」與「註冊」的範例。 |
| 第三方合作夥伴 | 合作夥伴只看文件,若文件中有具體範例,可快速完成對接測試。 | 在付款 API 中加入 example,示範成功/失敗的回傳結構。 |
| 自動產生 API 客戶端 | OpenAPI 生成的 SDK 會使用 example 產生測試代碼。 |
使用 openapi-generator 產生的 TypeScript 客戶端會自動帶入範例。 |
| 內部測試環境 | CI/CD 流程可利用 example 直接產生測試資料,驗證 API 正確性。 |
在測試腳本中讀取 MyModel.schema()["example"] 作為測試 payload。 |
| 文件維護 | 隨著模型變更,schema_extra 直接寫在模型檔案中,文件自動同步更新。 |
當新增 age 欄位時,只需在 schema_extra["properties"]["age"] 補上說明與範例。 |
總結
schema_extra是 Pydantic 為 OpenAPI 文件提供自訂資訊的關鍵工具。- 透過
example、examples、properties等屬性,我們可以在 Swagger UI 中呈現完整、正確且易於理解的範例,提升前後端協作效率。 - 使用時要注意 範例與驗證的一致性、避免過度堆砌資訊,並建議 加入自動化測試 以確保文件永遠保持正確。
- 在實務上,
schema_extra幫助前端快速測試、第三方合作、SDK 生成與 CI/CD 測試等多種情境,是真正讓 API 可用、可測、可維護 的加分項。
掌握了 schema_extra 的寫法與最佳實踐後,你的 FastAPI 專案將不再只是功能完整的後端服務,更會是一套 清晰、可自說明的 API 生態系統。祝開發順利!