跳轉到

OpenAPI Schema 進階用法

複雜數據模型與 Schema 定制

複雜嵌套模型

FastAPI 支持複雜的嵌套模型,自動轉換為 OpenAPI Schema:

from typing import List, Optional, Set
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl

class Image(BaseModel):
    url: HttpUrl
    name: str

class Item(BaseModel):
    name: str
    price: float
    images: Optional[List[Image]] = None
    tags: Set[str] = set()

app = FastAPI()

@app.post("/items/")
async def create_item(item: Item):
    return item

自定義 JSON Schema 屬性

使用 Pydantic 的 Fieldmodel_config 自定義 Schema:

from fastapi import FastAPI
from pydantic import BaseModel, Field

class Item(BaseModel):
    name: str = Field(..., title="名稱", example="Foo")
    price: float = Field(..., gt=0, example=35.4)

    model_config = {
        "json_schema_extra": {
            "examples": [
                {"name": "Foo", "price": 35.4}
            ]
        }
    }

app = FastAPI()

@app.post("/items/")
async def create_item(item: Item):
    return item

枚舉類型與 OpenAPI

Python 的枚舉類型自動轉換為 OpenAPI 中的枚舉:

from enum import Enum
from fastapi import FastAPI

class ModelName(str, Enum):
    alexnet = "alexnet"
    resnet = "resnet"
    lenet = "lenet"

app = FastAPI()

@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
    return {"model_name": model_name}

高級類型約束

類型約束對比表

約束類型 說明 FastAPI/Pydantic 實現
anyOf 符合多個 schema 中的至少一個 Union[Type1, Type2]
oneOf 符合多個 schema 中的恰好一個 使用鑑別字段 (discriminator)
allOf 同時符合所有指定的 schema 類繼承 (Class inheritance)
not 不符合指定的 schema 自定義驗證器 (field_validator)

使用 anyOf (Union)

from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel

class StringModel(BaseModel):
    value: str

class NumberModel(BaseModel):
    value: float

app = FastAPI()

@app.post("/items/")
async def create_item(item: Union[StringModel, NumberModel]):
    return item

使用 oneOf (鑑別字段)

from typing import Literal, Union
from fastapi import FastAPI
from pydantic import BaseModel, Field

class Dog(BaseModel):
    pet_type: Literal["dog"]
    bark: bool = True

class Cat(BaseModel):
    pet_type: Literal["cat"]
    meow: bool = True

class Pet(BaseModel):
    pet: Union[Dog, Cat] = Field(..., discriminator="pet_type")

app = FastAPI()

@app.post("/pets/")
async def create_pet(pet_info: Pet):
    return pet_info

使用 allOf (繼承)

from fastapi import FastAPI
from pydantic import BaseModel

class NameModel(BaseModel):
    name: str

class AgeModel(BaseModel):
    age: int

class Person(NameModel, AgeModel):
    pass

app = FastAPI()

@app.post("/persons/")
async def create_person(person: Person):
    return person

使用 not (排除)

from fastapi import FastAPI
from pydantic import BaseModel, field_validator

class User(BaseModel):
    username: str

    @field_validator('username')
    def username_not_reserved(cls, v):
        if v in ["admin", "root", "superuser"]:
            raise ValueError("保留用戶名")
        return v

app = FastAPI()

@app.post("/users/")
async def create_user(user: User):
    return user

自定義 OpenAPI 文檔

文檔自定義選項

自定義項 說明 使用方式
操作 ID 路徑操作的唯一標識符 @app.get(..., operation_id="get_item")
標籤 對端點進行分類分組 @app.get(..., tags=["users"])
排除端點 從文檔中隱藏端點 @app.get(..., include_in_schema=False)
自定義配置 添加額外的 OpenAPI 信息 @app.get(..., openapi_extra={...})

自定義操作 ID 與標籤

from fastapi import FastAPI

app = FastAPI(
    openapi_tags=[
        {"name": "users", "description": "用戶相關操作"},
        {"name": "items", "description": "項目相關操作"},
    ]
)

@app.get("/users/", tags=["users"], operation_id="list_users")
async def read_users():
    return [{"name": "Harry"}, {"name": "Ron"}]

高級響應處理

響應配置選項

配置項 說明 使用方式
response_model 響應數據模型 @app.get(..., response_model=Item)
response_model_include 只包含指定字段 @app.get(..., response_model_include={"name"})
response_model_exclude 排除指定字段 @app.get(..., response_model_exclude={"description"})
responses 定義不同狀態碼的響應 @app.get(..., responses={404: {"model": Error}})

動態響應模型

from typing import Union
from fastapi import FastAPI
from pydantic import BaseModel

class Item(BaseModel):
    id: str
    value: str

class Message(BaseModel):
    message: str

app = FastAPI()

@app.get("/items/{item_id}", response_model=Union[Item, Message])
async def read_item(item_id: str):
    if item_id == "foo":
        return {"id": "foo", "value": "bar"}
    return {"message": "Item not found"}

響應模型過濾

from fastapi import FastAPI
from pydantic import BaseModel

class Item(BaseModel):
    name: str
    description: str
    price: float
    tax: float

app = FastAPI()

@app.get(
    "/items/{item_id}",
    response_model=Item,
    response_model_include={"name", "price"}
)
async def read_item(item_id: str):
    return {
        "name": "Example",
        "description": "Full description",
        "price": 50.2,
        "tax": 10.5
    }

安全性與認證

支持的安全方案

安全方案 說明 FastAPI 類
OAuth2 密碼流 使用用戶名和密碼獲取令牌 OAuth2PasswordBearer
OAuth2 客戶端憑證 使用客戶端 ID 和密鑰 OAuth2ClientCredentials
API 密鑰 (Header) 在標頭中傳遞 API 密鑰 APIKeyHeader
API 密鑰 (Query) 在查詢參數中傳遞 API 密鑰 APIKeyQuery
API 密鑰 (Cookie) 在 Cookie 中傳遞 API 密鑰 APIKeyCookie

OAuth2 基本示例

from fastapi import Depends, FastAPI, Security
from fastapi.security import OAuth2PasswordBearer

app = FastAPI()

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

@app.get("/items/")
async def read_items(token: str = Depends(oauth2_scheme)):
    return {"token": token}

API 密鑰示例

from fastapi import Depends, FastAPI, Security
from fastapi.security import APIKeyHeader

app = FastAPI()

api_key_header = APIKeyHeader(name="X-API-Key")

@app.get("/items/")
async def read_items(api_key: str = Depends(api_key_header)):
    return {"api_key": api_key}

依賴項與 OpenAPI

依賴項在 OpenAPI 中的表現

from fastapi import Depends, FastAPI, Query

app = FastAPI()

async def common_params(
    q: str = Query(None, min_length=3),
    skip: int = Query(0, ge=0),
    limit: int = Query(10, le=100)
):
    return {"q": q, "skip": skip, "limit": limit}

@app.get("/items/")
async def read_items(commons: dict = Depends(common_params)):
    return commons

路徑依賴項

from fastapi import Depends, FastAPI, Header, HTTPException

app = FastAPI()

async def verify_token(x_token: str = Header(...)):
    if x_token != "valid-token":
        raise HTTPException(status_code=400, detail="Invalid token")
    return x_token

@app.get("/items/", dependencies=[Depends(verify_token)])
async def read_items():
    return [{"item": "Foo"}]

實用案例

多態性 API 端點

from typing import Literal, Union
from fastapi import FastAPI
from pydantic import BaseModel, Field

app = FastAPI()

class BasePet(BaseModel):
    pet_type: str
    name: str

class Dog(BasePet):
    pet_type: Literal["dog"]
    breed: str

class Cat(BasePet):
    pet_type: Literal["cat"]
    breed: str

class PetRegistration(BaseModel):
    owner_name: str
    pet: Union[Dog, Cat] = Field(..., discriminator="pet_type")

@app.post("/register/")
async def register_pet(registration: PetRegistration):
    return registration

複雜驗證規則

from datetime import date
from fastapi import FastAPI
from pydantic import BaseModel, field_validator

app = FastAPI()

class BookingDate(BaseModel):
    check_in: date
    check_out: date

    @field_validator('check_out')
    def check_dates(cls, v, info):
        if 'check_in' in info.data and v <= info.data['check_in']:
            raise ValueError('退房日期必須晚於入住日期')
        return v

@app.post("/bookings/")
async def create_booking(booking: BookingDate):
    return booking

常用 Schema 定制技巧

常用 Field 參數

參數 說明 示例
default 默認值 Field(default=0)
title 字段標題 Field(title="項目名稱")
description 字段描述 Field(description="項目的詳細描述")
example 示例值 Field(example="範例值")
gt/ge 大於/大於等於 Field(ge=0)
lt/le 小於/小於等於 Field(lt=100)
min_length/max_length 字符串長度限制 Field(min_length=3, max_length=50)
regex 正則表達式 Field(regex="^[a-z]+$")

自定義 OpenAPI 示例

from fastapi import FastAPI, Body
from pydantic import BaseModel

class Item(BaseModel):
    name: str
    price: float

    model_config = {
        "json_schema_extra": {
            "examples": [
                {
                    "name": "Foo",
                    "price": 35.4
                }
            ]
        }
    }

app = FastAPI()

@app.post("/items/")
async def create_item(
    item: Item = Body(
        ...,
        examples=[
            {
                "summary": "基本示例",
                "value": {
                    "name": "Foo",
                    "price": 35.4
                }
            },
            {
                "summary": "高價示例",
                "value": {
                    "name": "Bar",
                    "price": 135.4
                }
            }
        ]
    )
):
    return item

總結

OpenAPI Schema 進階用法的主要優勢:

功能 優勢
複雜數據模型 支持嵌套、繼承和複雜關係
高級類型約束 提供靈活的數據驗證機制
自定義文檔 改善 API 文檔的組織和可讀性
高級響應處理 精確控制 API 輸出
安全性與認證 內建多種安全機制並反映在文檔中
依賴項整合 簡化代碼並自動生成文檔

這些進階功能使 FastAPI 成為構建複雜、高性能 API 的理想選擇,同時保持了出色的文檔和類型安全性。