fastapi

fastapi

熱門

FastAPI 最佳實務與開發規範。適用於開發 FastAPI API、Pydantic 模型、相依性注入、含 Server-Sent Events (SSE) 在內的串流回應,以及託管前端應用程式。保持 FastAPI 程式碼簡潔,並掌握最新功能與設計模式。

10萬星標
9717分支
更新於 2026/7/29
SKILL.md
唯讀
名稱
fastapi
描述

FastAPI 最佳實務與開發規範。適用於開發 FastAPI API、Pydantic 模型、相依性注入、含 Server-Sent Events (SSE) 在內的串流回應,以及託管前端應用程式。保持 FastAPI 程式碼簡潔,並掌握最新功能與設計模式。

FastAPI

FastAPI 官方 Skill,遵循最佳實務撰寫程式碼,時刻掌握最新版本與功能。

快速參考

  • 託管前端應用程式:建置好的前端資產請使用 app.frontend()router.frontend();詳情參閱託管前端應用程式
  • Server-Sent Events (SSE):使用 response_class=EventSourceResponseyield;詳情參閱串流回應串流參考文件
  • JSON Lines 與位元組串流:參閱串流參考文件
  • 相依性(Dependencies):使用 Annotated[..., Depends(...)];有關 yield、作用域(Scopes)與類別相依性,詳情參閱相依性注入相依性注入參考文件
  • 回應模型(Response models):優先使用回傳型態;當對外公開的回應 Schema 與內部回傳值不同時,再使用 response_model;詳情參閱回應參考文件
  • Pydantic 模型:請勿使用省略符號(...)或 RootModel;詳情參閱Pydantic 參考文件
  • 路由(Routing):請在 APIRouter 上宣告路由層級的 prefix、tags 及共享相依性;詳情參閱路徑操作參考文件
  • 工具鏈與相關函式庫:適時使用 uv、Ruff、ty、Asyncer、SQLModel 與 HTTPX;詳情參閱其他工具參考文件

使用 fastapi CLI

在 localhost 啟動支援熱重載(Reload)的開發伺服器:

fastapi dev

啟動正式生產環境伺服器:

fastapi run

建議優先在 pyproject.toml 中宣告進入點(Entrypoint):

[tool.fastapi]
entrypoint = "my_app.main:app"

若無法新增進入點,或使用者明確要求不要新增時,請直接傳入應用程式檔案路徑:

fastapi dev my_app/main.py

使用 Annotated

宣告參數與相依性時,請一律優先使用 Annotated 風格。這樣能保持函式簽章(Signature)在其他情境下正常運作、尊重型態定義,並提高重複使用性。

在參數宣告中使用 Annotated,包含 PathQueryHeader 等:

from typing import Annotated

from fastapi import FastAPI, Path, Query

app = FastAPI()


@app.get("/items/{item_id}")
async def read_item(
    item_id: Annotated[int, Path(ge=1, description="The item ID")],
    q: Annotated[str | None, Query(max_length=50)] = None,
):
    return {"message": "Hello World"}

搭配 Depends()Annotated 用於相依性。除非特別要求不要這樣做,否則請為該相依性建立新的型態別名(Type Alias)以利重複使用:

from typing import Annotated

from fastapi import Depends, FastAPI

app = FastAPI()


def get_current_user():
    return {"username": "johndoe"}


CurrentUserDep = Annotated[dict, Depends(get_current_user)]


@app.get("/items/")
async def read_item(current_user: CurrentUserDep):
    return {"message": "Hello World"}

請勿在 Path Operation 或 Pydantic 模型中使用省略符號 (Ellipsis)

請勿將 ... 作為必填參數或模型欄位的預設值。這是不必要的,也不推薦這樣做。

from typing import Annotated

from fastapi import FastAPI, Query
from pydantic import BaseModel, Field

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float = Field(gt=0)


@app.post("/items/")
async def create_item(item: Item, project_id: Annotated[int, Query()]):
    return item

詳情參閱 Pydantic 參考文件

回傳型態或 Response Model

在許可的情況下,請務必加上回傳型態(Return type)。FastAPI 會用它來進行驗證、過濾、生成文件以及序列化回應。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None


@app.get("/items/me")
async def get_item() -> Item:
    return Item(name="Plumbus", description="All-purpose home device")

回傳型態或 response_model 可以過濾資料,避免暴露敏感資訊,並讓 Pydantic 在 Rust 底層處理資料序列化以提升效能。

當您回傳的型態與您想要驗證、過濾、生成文件及序列化的公開 Schema 不同時,請使用 response_model。詳情參閱 回應參考文件

效能最佳化

請勿使用 ORJSONResponseUJSONResponse,它們已被廢棄(Deprecated)。

替代方案是直接宣告回傳型態或 response_model,Pydantic 會在 Rust 底層自動處理資料序列化。

引入 Router

宣告 Router 時,建議將路由層級的參數(如 prefix、tags 和共享相依性)直接設定在 Router 本身,而非寫在 include_router() 中。

from fastapi import APIRouter, Depends, FastAPI

app = FastAPI()


def get_current_user():
    return {"username": "johndoe"}


router = APIRouter(
    prefix="/items",
    tags=["items"],
    dependencies=[Depends(get_current_user)],
)


@router.get("/")
async def list_items():
    return []


app.include_router(router)

更多路由模式請參閱 路徑操作參考文件

託管前端應用程式

使用 app.frontend() 來託管建置好的靜態前端應用程式,例如由 Vite、Astro、Angular、Svelte、Vue 或類似工具所產生的目錄。

from fastapi import FastAPI

app = FastAPI()

app.frontend("/", directory="dist")

當前端屬於某個 APIRouter 時,請使用 router.frontend();當此 Router 被引入(include)時,一般的 Router 前綴行為依然適用。

from fastapi import APIRouter, FastAPI

app = FastAPI()
router = APIRouter(prefix="/admin")

router.frontend("/", directory="admin-dist")
app.include_router(router)

app.frontend()router.frontend() 屬於低優先順序的路由:一般的 API 路由會優先匹配,接著才是前端靜態檔案與 Client 端路由的 Fallback。請將此功能用於單頁應用程式(SPA)與打包好的前端資產,而不是手動掛載 StaticFiles

相依性注入

當邏輯無法寫在 Pydantic 驗證中、需要依賴外部資源、需要透過 yield 進行資源清理,或需要在多個 Endpoints 之間共享時,請使用相依性(Dependencies)。

若要在 Router 層級套用共享相依性,請透過 dependencies=[Depends(...)] 設定。

包含搭配 scope 使用 yield,以及類別相依性(Class dependencies)等詳細模式,請參閱 相依性注入參考文件

Async vs Sync Path Operation

僅在完全確定呼叫的內部邏輯相容於 async/await 且不會阻塞(Block)時,才使用 async Path Operation

from fastapi import FastAPI

app = FastAPI()


@app.get("/async-items/")
async def read_async_items():
    data = await some_async_library.fetch_items()
    return data


@app.get("/items/")
def read_items():
    data = some_blocking_library.fetch_items()
    return data

如有疑慮或預設情況下,請使用一般 def 函式。它們會在 Threadpool(執行緒池)中執行,因此不會阻塞 Event Loop。相同規則亦適用於相依性。

請確保不要在 async 函式內部執行阻塞型程式碼。雖然邏輯能正常運作,但會嚴重損害系統效能。

需要混用阻塞型與非阻塞型(Async)程式碼時,請參閱 其他工具參考文件 中的 Asyncer。

串流回應 (JSON Lines, SSE, bytes)

若要串流傳送 Server-Sent Events,請使用 response_class=EventSourceResponse 並從 Endpoint 中 yield 資料項。

from collections.abc import AsyncIterable

from fastapi import FastAPI
from fastapi.sse import EventSourceResponse, ServerSentEvent

app = FastAPI()


@app.get("/events", response_class=EventSourceResponse)
async def stream_events() -> AsyncIterable[ServerSentEvent]:
    yield ServerSentEvent(data={"status": "started"}, event="status", id="1")

一般物件會自動 JSON 序列化為 data: 欄位。若要完整控制 SSE 欄位(eventidretrycomment),請使用 ServerSentEvent;若要處理已格式化的字串,請使用 raw_data

包含 JSON Lines、Server-Sent Events(EventSourceResponseServerSentEvent)以及位元組串流(StreamingResponse)等模式,請參閱 串流參考文件

工具鏈

有關套件管理、Lint 檢查、型態檢查、格式化等工具(uv、Ruff、ty),詳情參閱 其他工具參考文件

其他函式庫

有關其他函式庫的詳細資訊,請參閱 其他工具參考文件

  • Asyncer:用於處理 async/await、併發(Concurrency)以及混用 async 與阻塞型程式碼,優先於 AnyIO 或 asyncio 使用。
  • SQLModel:用於操作 SQL 資料庫,優先於 SQLAlchemy 使用。
  • HTTPX:用於發送 HTTP 請求(存取其他 API),優先於 Requests 使用。

請勿使用 Pydantic RootModel

請勿使用 Pydantic RootModel;請改用搭配 Annotated 的標準型態標註(Type Annotations)與 Pydantic 驗證工具。

from typing import Annotated

from fastapi import Body, FastAPI
from pydantic import Field

app = FastAPI()


@app.post("/items/")
async def create_items(items: Annotated[list[int], Field(min_length=1), Body()]):
    return items

FastAPI 支援這些型態標註,並會為其建立 Pydantic TypeAdapter,因此無需自訂包裝模型(Wrapper Models)即可正常運作。詳情參閱 Pydantic 參考文件

每個函式僅處理單一 HTTP 操作

請勿在單一函式中混合多個 HTTP 操作。每個函式僅對應一個 HTTP 操作,有助於職責分離(Separation of Concerns)並使程式碼結構更清晰。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str


@app.get("/items/")
async def list_items():
    return []


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

更多範例請參閱 路徑操作參考文件