前請提要 最近團隊的小朋友作的系統發生了錯誤。
在追查的過程之中, 小朋友說了一個驚人的事實 ,Python 的 FastAPI Web 框架,發生 422 錯誤時(輸入的參數類別錯誤),無法追踪 Request$$ 當然這不是事實,那麼 FastAPI 應該怎麼處理呢?
本文 讓我們先簡單實作一個 Fast API
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 from fastapi import FastAPIfrom pydantic import BaseModelapp = FastAPI() class Item (BaseModel ): name: str price: float description: str = None @app.post("/items/" ) async def create_item (item: Item ): if item.price <= 0 : return {"error" : "Price must be greater than 0" } return {"message" : "Item created successfully!" , "item" : item}
接下來,讓我試著用不正確的方式呼叫 API,並且得到一個 422 的錯誤
1 2 3 4 curl -X POST "http://127.0.0.1:8000/items/" -H "Content-Type: application/json" -d '{"item": "should be number", "price": 10.5}'
FastAPI 會提供 Client 端非常友善的資訊
1 2 3 4 5 6 7 8 9 10 11 12 { "detail" : [ { "type" : "missing" , "loc" : [ "body" , "name" ] , "msg" : "Field required" , "input" : { "item" : "should be number" , "price" : 10.5 } } ] }
但在 Server 端只會有類似以下的資訊,這以後端的角度要排查錯誤會非常不便
1 INFO: 127.0.0.1:57617 - "POST /items/ HTTP/1.1" 422 Unprocessable Entity
Server Side 有沒有什麼好方法可以協助我們 Debug 呢?
解決方法:Middleware 這其實是 web 開發者的小常識才對, 實作如下,
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 from fastapi import FastAPI,Requestfrom pydantic import BaseModelimport loggingfrom datetime import datetimeapp = FastAPI() logging.basicConfig(level=logging.INFO, format ="%(asctime)s - %(message)s" ) class Item (BaseModel ): name: str price: float description: str = None @app.middleware("http" ) async def log_requests (request: Request, call_next ): request_time = datetime.utcnow() logging.info(f"Incoming request at {request_time} " ) logging.info(f"Method: {request.method} | Path: {request.url.path} " ) try : body = await request.json() logging.info(f"Request Body: {body} " ) except Exception: logging.info("No JSON body or failed to parse." ) response = await call_next(request) logging.info(f"Response status: {response.status_code} " ) return response @app.post("/items/" ) async def create_item (item: Item ): if item.price <= 0 : return {"error" : "Price must be greater than 0" } return {"message" : "Item created successfully!" , "item" : item}
Request 送進來時 Server Side 就會如下記錄
1 2 3 4 5 2025-01-03 03:37:37,294 - Incoming request at 2025-01-02 19:37:37.294509 2025-01-03 03:37:37,294 - Method: POST | Path: /items/ 2025-01-03 03:37:37,294 - Request Body: {'item' : 'should be number' , 'price' : 10.5} 2025-01-03 03:37:37,295 - Response status: 422 INFO: 127.0.0.1:59545 - "POST /items/ HTTP/1.1" 422 Unprocessable Entity
心得 回到我們原本的情境,我們真正要解決的問題是,
|發生異常時,Server Side 要可以追蹤錯誤
因為是 FastAPI 所以沒有辦法追蹤錯誤,是非常錯誤判斷
在 Google 與 AI 工具這麼方便的時代,應該要能正確的提出問題。
ex: FastAPI 可以記錄什麼時候 request 送進來,並帶了什麼資訊嗎?
(fin)