On this page
เชื่อม API กับ DB (CRUD API)
ต่อ API เข้ากับฐานข้อมูล (บท 9) ทำ endpoint CRUD ครบ พร้อมแยก layer ให้เทสต์ง่าย
API ที่มีประโยชน์จริงต้องเก็บข้อมูลถาวร หัวข้อนี้รวม FastAPI (บทนี้) เข้ากับฐานข้อมูล (บท 9) เป็น CRUD API ที่ใช้งานได้จริง พร้อมแนวคิดการแยก layer ให้โค้ดสะอาดและเทสต์ง่าย
CRUD API เชื่อม DB
ตัวอย่างย่อ (ใช้ sqlite3 จากบท 9) แต่ละ endpoint map กับการกระทำกับ DB
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import sqlite3
app = FastAPI()
class Item(BaseModel):
name: str
price: float
def db():
conn = sqlite3.connect("shop.db")
conn.row_factory = sqlite3.Row # ให้ผลเป็น dict-like
return conn
@app.post("/items", status_code=201)
def create_item(item: Item):
conn = db()
cur = conn.execute(
"INSERT INTO items (name, price) VALUES (?, ?)", # ? กัน injection
(item.name, item.price),
)
conn.commit()
return {"id": cur.lastrowid, **item.model_dump()}
@app.get("/items/{item_id}")
def get_item(item_id: int):
row = db().execute("SELECT * FROM items WHERE id = ?", (item_id,)).fetchone()
if row is None:
raise HTTPException(status_code=404, detail="ไม่พบสินค้า")
return dict(row)HTTPException — ตอบ error ให้ถูก status
เมื่อไม่พบข้อมูลหรือ input ผิด ให้ raise HTTPException พร้อม status code ที่เหมาะ (404, 400) แทนการคืน None เงียบ ๆ
from fastapi import HTTPException
if row is None:
raise HTTPException(status_code=404, detail="ไม่พบ")แยก layer: route / service / db
อย่ายัด logic ทั้งหมดใน route — แยกเป็นชั้น ทำให้เทสต์และดูแลง่าย (เชื่อม clean code บท 7 + testing บท 6)
- Route layer — รับ request, ตอบ response (บาง ๆ)
- Service layer — business logic (เทสต์ได้โดยไม่ต้องมี HTTP)
- DB layer — คุยกับฐานข้อมูล
ถ้า logic อยู่ใน service ธรรมดา (ไม่ผูกกับ FastAPI) เราเขียน unit test เรียกตรง ๆ ได้โดยไม่ต้องสตาร์ท server — ต่อยอดจากหลัก Dependency Inversion (บท 7) และการเทสต์ (บท 6)
สรุปหัวข้อนี้
- CRUD API: map endpoint กับ INSERT/SELECT/UPDATE/DELETE
- ใช้ ? placeholder กัน SQL injection เหมือนเดิม
- raise HTTPException(404/400) ตอบ error ให้ถูก status
- แยก route/service/db layer — เทสต์ service ได้โดยไม่ต้องมี HTTP
1) ทำ CRUD API ของ resource สักตัว (เช่น tasks) เชื่อม sqlite3 2) ใส่ HTTPException 404 เมื่อไม่พบ 3) แยก logic การบันทึกออกเป็นฟังก์ชัน service 4) เขียน unit test ให้ service โดยไม่ต้องสตาร์ท server