Error Handling
HTTPException — เครื่องมือ error หลัก
หัวข้อที่มีชื่อว่า “HTTPException — เครื่องมือ error หลัก”ใน Express คุณเรียก res.status(404).json(...) หรือโยน error เข้า next(err) ส่วนใน FastAPI คุณ raise HTTPException ออกไปตรง ๆ เป็น Python exception ธรรมดาที่ FastAPI คอยดักจับแล้วแปลงเป็น HTTP response ให้ ผลคือ error path หน้าตาเหมือนโค้ด Python ปกติ
// Express — return error responseapp.get('/items/:id', async (req, res) => { const item = await db.findById(req.params.id); if (!item) return res.status(404).json({ message: 'Item not found' }); res.json(item);});
// NestJS — throw built-in exception@Get(':id')async findOne(@Param('id') id: string) { const item = await this.itemsService.findOne(+id); if (!item) throw new NotFoundException('Item not found'); return item;}# FastAPI — raise HTTPExceptionfrom fastapi import FastAPI, HTTPException
app = FastAPI()
@app.get("/items/{item_id}")async def get_item(item_id: int): item = await db.find_by_id(item_id) if not item: raise HTTPException(status_code=404, detail="Item not found") return item
# detail เป็น dict ได้สำหรับ structured errorsraise HTTPException( status_code=422, detail={"field": "price", "message": "must be positive"},)Custom exception handlers
หัวข้อที่มีชื่อว่า “Custom exception handlers”สำหรับ application-wide error handling เทียบเท่ากับ Express’s (err, req, res, next) error middleware FastAPI ใช้ @app.exception_handler
// Express global error middlewareapp.use((err, req, res, next) => { console.error(err.stack); if (err.name === 'ValidationError') { return res.status(400).json({ error: err.message }); } res.status(500).json({ error: 'Internal Server Error' });});# FastAPI custom exception handlerfrom fastapi import FastAPI, Requestfrom fastapi.responses import JSONResponse
class ItemNotFoundError(Exception): def __init__(self, item_id: int): self.item_id = item_id
app = FastAPI()
@app.exception_handler(ItemNotFoundError)async def item_not_found_handler(request: Request, exc: ItemNotFoundError): return JSONResponse( status_code=404, content={"error": f"Item {exc.item_id} does not exist"}, )
@app.get("/items/{item_id}")async def get_item(item_id: int): raise ItemNotFoundError(item_id=item_id) # จับอัตโนมัติOverride default 422 handler
หัวข้อที่มีชื่อว่า “Override default 422 handler”validation error handler ที่ FastAPI ให้มาในตัวจะคืน RequestValidationError ออกมา ซึ่งคุณ override เองได้ เพื่อให้รูปแบบตรงกับ error envelope ของ API
// Zod error shaping ใน Expressapp.use((err, req, res, next) => { if (err instanceof ZodError) { return res.status(400).json({ errors: err.errors.map(e => ({ path: e.path, message: e.message })), }); } next(err);});# Override FastAPI's default validation error handlerfrom fastapi import FastAPI, Request, statusfrom fastapi.exceptions import RequestValidationErrorfrom fastapi.responses import JSONResponse
app = FastAPI()
@app.exception_handler(RequestValidationError)async def validation_exception_handler( request: Request, exc: RequestValidationError): return JSONResponse( status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, content={ "errors": [ {"field": e["loc"][-1], "message": e["msg"]} for e in exc.errors() ] }, )ลองเล่น — Python exception hierarchy
หัวข้อที่มีชื่อว่า “ลองเล่น — Python exception hierarchy”FastAPI HTTPException คือ Python exception ธรรมดา สำรวจวิธีที่ raise และ except ทำงานด้วย stdlib:
# Python exceptions — กลไกเดียวกับที่ FastAPI ใช้class AppError(Exception): \"\"\"Base class for application errors.\"\"\" def __init__(self, message: str, status_code: int = 500): self.message = message self.status_code = status_code super().__init__(message)
class NotFoundError(AppError): def __init__(self, resource: str, resource_id: int): super().__init__(f"{resource} {resource_id} not found", 404) self.resource = resource self.resource_id = resource_id
class ValidationError(AppError): def __init__(self, field: str, message: str): super().__init__(f"[{field}] {message}", 422)
def find_item(item_id: int): if item_id <= 0: raise ValidationError("item_id", "must be a positive integer") if item_id > 100: raise NotFoundError("Item", item_id) return {"id": item_id, "name": "Widget"}
for test_id in [0, 42, 999]: try: result = find_item(test_id) print(f"OK {test_id:4d} -> {result}") except AppError as e: print(f"ERR {test_id:4d} -> {e.status_code} {e.message}")Loading Python runtime (first run only)…