Notes & software courses · Free to learn
Aph's Blog
On this page

เชื่อม API กับ DB (CRUD API)

👋 อ่านฟรีทั้งหมดบน Aph's Blog — เนื้อหาภาษาไทย ทำตามทีละหน้าใน sidebar ได้เลย หากมีข้อเสนอแนะหรืออยากให้เพิ่มหัวข้อไหน บอกได้เสมอ

ต่อ API เข้ากับฐานข้อมูล (บท 9) ทำ endpoint CRUD ครบ พร้อมแยก layer ให้เทสต์ง่าย

API ที่มีประโยชน์จริงต้องเก็บข้อมูลถาวร หัวข้อนี้รวม FastAPI (บทนี้) เข้ากับฐานข้อมูล (บท 9) เป็น CRUD API ที่ใช้งานได้จริง พร้อมแนวคิดการแยก layer ให้โค้ดสะอาดและเทสต์ง่าย

CRUD API เชื่อม DB

ตัวอย่างย่อ (ใช้ sqlite3 จากบท 9) แต่ละ endpoint map กับการกระทำกับ DB

python
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 เงียบ ๆ

python
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 ออกจาก route = เทสต์ง่าย

ถ้า 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