錯誤處理
驗證失敗時 FastAPI 已經會回 422。業務上的失敗——找不到資源、沒權限、衝突——要你自己用 HTTPException 丟出,客戶端才能依狀態碼處理,而不是從 200 的 JSON 裡猜。
用 HTTPException 表達可預期錯誤
from fastapi import FastAPI, HTTPException
app = FastAPI()
fake_db = {"1": {"name": "筆記本"}}
@app.get("/items/{item_id}")
def read_item(item_id: str):
item = fake_db.get(item_id)
if item is None:
raise HTTPException(status_code=404, detail="找不到這個商品")
return item
raise 之後函式結束,框架把 detail 序列化成 JSON:{"detail": "找不到這個商品"}。可加上 headers,例如認證失敗時回 WWW-Authenticate。
常用狀態碼:
| 狀態碼 | 何時使用 |
|---|---|
| 400 | 請求語法對,但業務規則不接受 |
| 401 | 未提供或無效的認證 |
| 403 | 已認證,但沒有權限 |
| 404 | 資源不存在 |
| 409 | 與現有資料衝突(例如帳號已註冊) |
| 422 | 驗證失敗(框架自動處理居多) |
detail 可以是字串,也可以是結構化資料(list / dict),方便前端對欄位顯示錯誤。
不要用例外處理「正常流程」以外的事
HTTPException 給呼叫端預期得到的失敗。程式自己炸了(資料庫斷線、未捕捉的 bug)應回 500,並靠日誌排查;不要把內部 stack 傳給客戶端。
若要統一包裝某種錯誤,可用例外處理器:
from fastapi import Request
from fastapi.responses import JSONResponse
class UnicornException(Exception):
def __init__(self, name: str):
self.name = name
@app.exception_handler(UnicornException)
async def unicorn_handler(request: Request, exc: UnicornException):
return JSONResponse(
status_code=418,
content={"message": f"{exc.name} 現在忙線中"},
)
入門階段不必急著自訂全域格式;先把每個端點的 404 / 401 / 403 丟對,文件與客戶端就已經好用很多。
進一步學習
- 官方:處理錯誤
- MDN:HTTP 回應狀態碼
- 下一頁:非同步