Python FastAPI 入門與 Pydantic 驗證 快速實現高效 API 與自動化文件

me
林彥成
2021-10-08 | 3 min.
文章目錄
  1. 1. 什麼是 FastAPI 及其核心優勢?
  2. 2. 什麼是 FastAPI?為什麼它是當今首選的 API 框架?
  3. 3. FastAPI 教學範例:快速上手與啟動
    1. 3.1. Path Param 與路由順序
    2. 3.2. Query Param 參數傳遞
    3. 3.3. Pydantic 資料驗證與 Input Validation
    4. 3.4. Response Validation 回傳格式驗證
  4. 4. FAQ:Python FastAPI 開發常見問題
    1. 4.1. Q1:FastAPI 與 Flask、Django 相比,該如何選擇?
    2. 4.2. Q2:為什麼 FastAPI 推薦使用非同步 API 開發 (async/await)?
    3. 4.3. Q3:自動生成的 Swagger 文件在正式環境中會有安全風險嗎?

什麼是 FastAPI 及其核心優勢?

FastAPI 是一款現代、高效能的 Python Web 框架,專為開發高品質的 API 而生。其 Python FastAPI 入門 的核心價值在於:1. 開發速度極快:結合 Python 型別提示 (Type Hints),能大幅減少約 40% 的開發錯誤;2. API 自動化文件:內建符合 OpenAPI 標準的 Swagger UI 與 ReDoc 介面,免去手動維護 Spec 的煩惱;3. 強大的數據保護:深度整合 Pydantic 資料驗證,確保輸入輸出格式精確無誤;4. 卓越效能:支援 非同步 API 開發 (ASGI),有效解決 Python GIL 效能瓶頸。透過簡單的 FastAPI 教學範例,您只需數行程式碼即可部署穩健且具備自動化文件說明的後端服務。


什麼是 FastAPI?為什麼它是當今首選的 API 框架?

FastAPI 是一個現代、高效能的 Python Web 框架,旨在提供開發者一個能快速開發環境。它最大的優點在於透過自動產生文件與支援型別確認,顯著減少開發過程中的錯誤。

根據官方文件,使用 FastAPI 能夠減少大約 40% 的人為錯誤,是進行 Python FastAPI 入門學習的最佳起點。

FastAPI 的核心優勢包含:

  • Type Hint 支援:全面整合 Python 型別提示,增加程式可讀性,檢查變數型態更方便,並由 Pydantic 資料驗證 強力驅動。
  • 符合 OpenAPI 標準:自動生成配置檔,無縫對接各種 API 測試工具。
  • API 自動化文件:解決以往 API Spec 管理困難的問題,不需手動撰寫 swagger.json 即可產生美觀的互動式頁面。
  • 解決 Python GIL 限制:支援 ASGI (Asynchronous Server Gateway Interface),讓您能輕鬆進行非同步 API 開發,大幅提升並行處理能力。

FastAPI 教學範例:快速上手與啟動

沒有最好的工具,只有最適合的工具。在嘗試過多款 Web 框架後,小編強烈推薦 FastAPI 給追求效率與效能的開發者。

簡單撰寫並啟動後,除了程式定義的路徑外,FastAPI 還會自動為您生成兩款熱門的API 自動化文件

  • /docs:產生 Swagger UI 文件頁面,支援 Live Demo 直接測試 API。
  • /redoc:產生 ReDoc 文件頁面,提供更為簡潔專業的文件檢視體驗。
  • /openapi.json:產生的標準 JSON 配置檔,可拿去如 Mock Server 等平台利用。
  1. 安裝
1
pip install fastapi uvicorn
  1. 建立一個範例檔 demo.py
1
2
3
4
5
6
7
8
from fastapi import FastAPI
app = FastAPI()

@app.get('/book/{book_id}')
def get_book_by_id(book_id: int):
return {
'book_id': book_id
}
  1. 執行
1
uvicorn demo:app --reload

到可以線上互動的文件去觀察目前的情況:

Swagger: /docs (圖片來源: https://fastapi.tiangolo.com/)

ReDoc: /redoc (圖片來源: https://fastapi.tiangolo.com/)

Path Param 與路由順序

FastAPI 教學範例中,您可以定義動態路由。路由的比對是照程式碼順序進行的,因此務必確認 /users/me 這種特定路徑放在變數路徑 /users/{user_id} 之前。

1
2
3
4
5
6
7
8
@app.get("/users/me")
async def read_user_me():
return {"user_id": "the current user"}


@app.get("/users/{user_id}")
async def read_user(user_id: str):
return {"user_id": user_id}

Query Param 參數傳遞

/get_book?book_id=132

  • 透過 Query Parameter 的方式帶入參數,FastAPI 會自動進行型別檢查。
1
2
3
4
5
@app.get('/get_book')
def get_book_by_id_via_query(book_id: int):
return {
'book_id': book_id
}

/book/1/with_mode?query_mode=author

  • 嘗試混和 url path 跟 query param
  • 定義 query_mode 的選項只有 authorcustomer 兩種
1
2
3
4
5
6
7
8
9
10
class QueryModeEnum(Enum):
AUTHOR = 'author'
CUSTOMER = 'customer'

@app.get('/book/{book_id}/with_mode')
def get_book_by_id_mix(book_id: int, query_mode: QueryModeEnum):
return {
'book_id': book_id,
'query_mode': query_mode,
}

Pydantic 資料驗證與 Input Validation

/book/{book_id}/with_validation

  • 利用 Pydantic 資料驗證 幫網址列的輸入參數加上防呆,例如要求數值大於 1。
  • 定義 Book 模型(BaseModel)來確保資料格式正確。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from fastapi import Path
from pydantic import BaseModel, Field

class Book(BaseModel):
bid: int = Field(..., ge=1, title='book id', description='`markdown`', example=5)
name: str = Field(..., min_length=2)
price: float = Field(..., gt=0)
category: BookCategory

@app.get('/book/{book_id}/with_validation')
def get_book_by_id_with_validation(book_id: int = Path(..., ge=1)):
return {
'book_id': book_id
}

@app.post('/book', response_model=Book)
def get_book_by_id_with_validation_and_some_extra_documnet(
payload: Book
):
payload.name += ' suffix'
return payload

Response Validation 回傳格式驗證

  • 定義 BookCategory 的列舉 (Enum),限定類別選項。
  • 透過 response_model 參數,確保 API 回傳的資料結構完全符合預期。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from pydantic import BaseModel, Field

class BookCategory(str, Enum):
comics = 'comics'
cooking = 'cooking'

class Book(BaseModel):
bid: int = Field(..., ge=1, title='book id', description='`markdown`', example=5)
name: str = Field(..., min_length=2)
price: float = Field(..., gt=0)
category: BookCategory

@app.get('/book/{book_id}/with_response_model', response_model=Book)
def get_book_by_id_with_validation_and_some_extra_documnet(
book_id: int = Path(..., ge=1, example=5)
):
return {'book_id': book_id}

# return {
# "bid": 5,
# "name": "string suffix",
# "price": 10,
# "category": "comics"
# }



FAQ:Python FastAPI 開發常見問題

Q1:FastAPI 與 Flask、Django 相比,該如何選擇?

A:Flask 輕量但缺乏型別檢查與文件自動化;Django 功能全面但較為沉重且學習曲線陡峭。如果您追求的是「現代化的開發體驗」(自動文件、強型別)與「極致的效能」(原生非同步支援),Python FastAPI 入門 是目前開發高性能微服務的最佳平衡點。

Q2:為什麼 FastAPI 推薦使用非同步 API 開發 (async/await)?

A:傳統 Python 同步框架在等待 I/O 操作(如查詢資料庫或打外部 API)時會阻塞整個進程。非同步 API 開發 允許單一工作進程 (Worker) 在等待期間處理其他請求,大幅提升了高併發場景下的吞吐量。這讓 FastAPI 在效能測試中能與 Node.js 或 Go 等高效能語言媲美。

Q3:自動生成的 Swagger 文件在正式環境中會有安全風險嗎?

A:是的。預設情況下 /docs 是公開的。在高品質的 API 自動化文件 管理中,建議在生產環境中透過環境變數關閉文件頁面,或者利用 FastAPI 內建的 Security 依賴項為文件路徑加上 HTTP Basic Auth 等驗證機制,確保內部接口文件不被外部惡意探測。



喜歡這篇文章,請幫忙拍拍手喔 🤣