快轉到主要內容
  1. 教學文章/

FastAPI:Python 最潮的 Web API 框架

·5 分鐘· loading · loading · ·
Python Fastapi Web Api Async
每日拍拍
作者
每日拍拍
科學家 X 科技宅宅
目錄
Python 學習 - 本文屬於一個選集。
§ 21: 本文

一. 前言
#

你有沒有想過,為什麼現在大家都在用 FastAPI?🚀

不管是做個小型 side project、寫個 LLM 的 API wrapper、還是搭建微服務架構,FastAPI 都是 Python 開發者的首選。它不只快(名字裡就有 Fast),而且自動生成 API 文件、支援型別驗證、還有原生的非同步支援。

今天拍拍君就帶大家從零開始,一步步用 FastAPI 建立一個完整的 API 服務!

二. 安裝
#

uvpip 都可以:

# 推薦用 uv(如果你還不知道 uv,可以看拍拍君的 [uv 教學](../python-uv/))
uv add fastapi uvicorn

# 或者用 pip
pip install fastapi uvicorn

這裡我們同時安裝了 uvicorn,它是一個高效能的 ASGI 伺服器,用來跑 FastAPI 應用程式。

確認安裝成功:

python -c "import fastapi; print(fastapi.__version__)"

三. 第一個 API:Hello World
#

建立一個 main.py

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"message": "拍拍君說 Hello! 👋"}

@app.get("/items/{item_id}")
def read_item(item_id: int, q: str | None = None):
    return {"item_id": item_id, "q": q}

啟動伺服器:

uvicorn main:app --reload

打開瀏覽器到 http://127.0.0.1:8000,你會看到 JSON 回應:

{"message": "拍拍君說 Hello! 👋"}

自動文件 ✨
#

FastAPI 最讚的功能之一:自動產生互動式 API 文件

  • Swagger UI:http://127.0.0.1:8000/docs
  • ReDoc:http://127.0.0.1:8000/redoc

不用額外設定,你的 API 文件就自動生成了,這在跟前端工程師協作時超級方便。

四. 請求與回應模型:搭配 Pydantic
#

FastAPI 和 Pydantic 是天生一對。用 Pydantic 模型來定義請求和回應的資料結構,FastAPI 會自動幫你做型別驗證。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

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

@app.post("/items/")
def create_item(item: Item):
    total = item.price + (item.tax or 0)
    return {
        "name": item.name,
        "total_price": total,
        "message": f"拍拍君幫你算好了!{item.name} 含稅共 {total} 元 💰"
    }

試試用 curl 發送 POST 請求:

curl -X POST http://127.0.0.1:8000/items/ \
  -H "Content-Type: application/json" \
  -d '{"name": "拍拍抱枕", "price": 299, "tax": 15}'

回應:

{
  "name": "拍拍抱枕",
  "total_price": 314,
  "message": "拍拍君幫你算好了!拍拍抱枕含稅共 314.0 元 💰"
}

如果送了不合法的資料(例如 price 放字串),FastAPI 會自動回傳 422 錯誤,附上清楚的錯誤訊息。省下一堆手動驗證的程式碼!

五. 完整 CRUD 範例
#

來做一個簡單的待辦事項 API:

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel

app = FastAPI(title="拍拍君的待辦事項 API")

class Todo(BaseModel):
    title: str
    done: bool = False

class TodoResponse(Todo):
    id: int

# 用 dict 模擬資料庫
todos: dict[int, Todo] = {}
counter = 0

@app.post("/todos/", response_model=TodoResponse, status_code=201)
def create_todo(todo: Todo):
    global counter
    counter += 1
    todos[counter] = todo
    return TodoResponse(id=counter, **todo.model_dump())

@app.get("/todos/", response_model=list[TodoResponse])
def list_todos():
    return [
        TodoResponse(id=tid, **t.model_dump())
        for tid, t in todos.items()
    ]

@app.get("/todos/{todo_id}", response_model=TodoResponse)
def get_todo(todo_id: int):
    if todo_id not in todos:
        raise HTTPException(status_code=404, detail="找不到這個待辦事項 😢")
    t = todos[todo_id]
    return TodoResponse(id=todo_id, **t.model_dump())

@app.put("/todos/{todo_id}", response_model=TodoResponse)
def update_todo(todo_id: int, todo: Todo):
    if todo_id not in todos:
        raise HTTPException(status_code=404, detail="找不到這個待辦事項 😢")
    todos[todo_id] = todo
    return TodoResponse(id=todo_id, **todo.model_dump())

@app.delete("/todos/{todo_id}")
def delete_todo(todo_id: int):
    if todo_id not in todos:
        raise HTTPException(status_code=404, detail="找不到這個待辦事項 😢")
    del todos[todo_id]
    return {"message": "已刪除!拍拍君幫你清掉了 🗑️"}

這就是一個完整的 CRUD API!搭配自動文件,你可以直接在 /docs 頁面測試所有端點。

六. 非同步支援
#

FastAPI 原生支援 async/await(想深入了解可以看 asyncio 教學):

import asyncio
from fastapi import FastAPI

app = FastAPI()

@app.get("/slow")
async def slow_endpoint():
    """模擬一個耗時的操作"""
    await asyncio.sleep(2)
    return {"message": "拍拍君等了 2 秒,但伺服器沒有被阻塞喔!⚡"}

@app.get("/fast")
async def fast_endpoint():
    return {"message": "這個超快的!"}

當你用 async def 定義端點時,FastAPI 會用非同步的方式處理請求。這表示在等待 I/O(例如資料庫查詢、外部 API 呼叫)時,伺服器可以同時處理其他請求,效能大幅提升。

💡 小提醒:如果你的函式裡沒有用到 await,用普通的 def 就好。FastAPI 會自動把它放到 thread pool 裡執行,不會阻塞事件迴圈。

七. 查詢參數與路徑參數
#

FastAPI 對參數的處理非常直覺:

from fastapi import FastAPI, Query, Path

app = FastAPI()

@app.get("/search/")
def search_items(
    keyword: str = Query(..., min_length=1, max_length=50, description="搜尋關鍵字"),
    page: int = Query(default=1, ge=1, description="頁碼"),
    size: int = Query(default=10, ge=1, le=100, description="每頁筆數"),
):
    return {
        "keyword": keyword,
        "page": page,
        "size": size,
        "message": f"拍拍君正在搜尋「{keyword}」第 {page} 頁..."
    }

@app.get("/users/{user_id}/posts/{post_id}")
def get_user_post(
    user_id: int = Path(..., ge=1, description="使用者 ID"),
    post_id: int = Path(..., ge=1, description="文章 ID"),
):
    return {"user_id": user_id, "post_id": post_id}

QueryPath 除了做驗證,還會自動出現在 API 文件中,讓你的 API 文件更完整。

八. 中介層與錯誤處理
#

自訂中介層(Middleware)
#

import time
from fastapi import FastAPI, Request

app = FastAPI()

@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    start_time = time.perf_counter()
    response = await call_next(request)
    process_time = time.perf_counter() - start_time
    response.headers["X-Process-Time"] = f"{process_time:.4f}"
    return response

自訂例外處理
#

from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

app = FastAPI()

class PypyException(Exception):
    def __init__(self, message: str):
        self.message = message

@app.exception_handler(PypyException)
async def pypy_exception_handler(request: Request, exc: PypyException):
    return JSONResponse(
        status_code=418,
        content={"detail": f"拍拍君遇到問題了:{exc.message} 🤔"},
    )

@app.get("/oops")
def trigger_error():
    raise PypyException("這是一個自訂錯誤示範")

九. 部署小技巧
#

開發完成後,部署到正式環境時有幾個重點:

# 正式環境不要用 --reload
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4

# 或者用 Docker(可以參考拍拍君的 Docker 教學 ../python-docker/)

一個簡單的 Dockerfile

FROM python:3.12-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

💡 推薦搭配:FastAPI + Docker + pre-commit + Ruff,這套組合拍拍君大力推薦!

結語
#

FastAPI 之所以這麼受歡迎,是因為它真的把開發者體驗做到了極致:

  • 型別提示 → 自動驗證 + 自動文件
  • 非同步支援 → 高效能
  • Pydantic 整合 → 資料模型一致
  • 自動 API 文件 → 省下溝通成本

不管你是要做 REST API、微服務、還是幫 LLM 做個 API wrapper,FastAPI 都是 2026 年 Python 開發者的必備技能。

趕快動手試試看吧!拍拍君相信你一定可以的 💪

延伸閱讀
#

Python 學習 - 本文屬於一個選集。
§ 21: 本文

相關文章

Streamlit:用 Python 快速打造互動式資料應用
·8 分鐘· loading · loading
Python Streamlit Data-Visualization Web-App Dashboard
Python Logging:別再 print 了,用正經的方式記錄日誌吧
·6 分鐘· loading · loading
Python Logging Debug 標準庫
Polars:比 Pandas 快 10 倍的 DataFrame 新選擇
·6 分鐘· loading · loading
Python Polars Dataframe 資料分析 Rust
PyTorch 神經網路入門:從零開始建立你的第一個模型
·5 分鐘· loading · loading
Python Pytorch Neural-Network Deep-Learning Machine-Learning
Ruff:用 Rust 寫的 Python Linter,快到你會懷疑人生
·4 分鐘· loading · loading
Python Ruff Linter Formatter Code-Quality
httpx:Python 新世代 HTTP 客戶端完全攻略
·4 分鐘· loading · loading
Python Httpx HTTP Async Requests