FastAPI: สร้าง API โคตรเร็ว โค้ดก็สวยด้วย

เฮ้ย ใครที่ยังใช้ Flask, Django REST framework แบบเดิมๆ อยู่บ้าง? ไม่ได้ว่านะ แต่ถ้าจะเริ่มโปรเจกต์ API ใหม่ๆ อ่ะ ลองดู FastAPI ดิ ว้าวมากบอกเลย โคตรชอบ

ทำไมต้อง FastAPI วะ?

เหตุผลง่ายๆ เลยนะ มันเร็ว! โคตรเร็วอะ เพราะมันสร้างมาบน Starlette (สำหรับเว็บพาร์ท) กับ Pydantic (สำหรับ Data Validation/Serialization) ซึ่งมันใช้ Async/Await ได้เต็มที่ เหมาะกับงาน I/O-bound สุดๆ ไม่ต้องรอคิวแบบที่พวก Sync Framework ต้องเจอ

แล้วที่เจ๋งกว่านั้นคือ มันใช้ Python Type Hint มาช่วย validate request/response data ให้เราเลย ไม่ต้องมานั่งเขียน if/else เช็ค request.json['field'] ให้เมื่อยมือ โค้ดจะอ่านง่ายขึ้นเยอะ แถมยังมี Auto-generated Docs ทั้ง Swagger UI กับ ReDoc ให้เราด้วย สะดวกชิบเป๋ง

มาลองดูกัน ง่ายนิดเดียว

ก่อนอื่นก็ pip install มันซะก่อน

pip install fastapi uvicorn[standard]

จากนั้นก็เขียนโค้ดง่ายๆ แบบนี้ใน main.py

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def read_root():
    return {"message": "Hello, FastAPI!"}

@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str | None = None):
    # item_id จะถูกแปลงเป็น int ให้อัตโนมัติ ถ้าใส่มาผิดก็ error เลย
    # q ก็เป็น optional string
    if q:
        return {"item_id": item_id, "q": q}
    return {"item_id": item_id}

# ลองรันด้วย:
# uvicorn main:app --reload

เห็นปะ โค้ดมันอ่านง่ายชิบเป๋ง แค่ใส่ Type Hint เข้าไป FastAPI ก็เข้าใจละว่าเราต้องการอะไร เจ๋ง!

Dependency Injection: ของดีที่ต้องใช้!

ทีเด็ดเลยคือ DI (Dependency Injection) เนี่ยแหละ ทำให้โค้ดเรา modular ขึ้นเยอะ เทสก็ง่าย ไม่ต้องยัดทุกอย่างลงไปในฟังก์ชันเดียว

สมมติเรามีฟังก์ชันที่ต้องต่อ DB หรือดึงค่า config อะไรบางอย่าง:

from fastapi import FastAPI, Depends, HTTPException, status
from typing import Annotated

app = FastAPI()

# สมมติว่านี่คือฟังก์ชันที่ไปดึง DB session มา
# ในโลกจริงอาจจะเป็นการต่อ database หรือดึงข้อมูล user จาก Header
async def get_current_user_id():
    # สมมติว่าดึงมาจาก database หรือ JWT token
    # อาจจะมีการเช็ค auth ตรงนี้ด้วย
    print("กำลังดึง User ID...")
    # user_id_from_db = await some_db_call()
    # ถ้ามีปัญหาอาจจะ raise HTTPException
    # raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authorized")
    return 123 # Hardcode ไปก่อนนะ

# เราสามารถใช้ Depends ใน parameter ของ endpoint ได้เลย
@app.get("/users/me")
async def read_current_user(user_id: Annotated[int, Depends(get_current_user_id)]):
    return {"current_user_id": user_id}

# ลองรันด้วย:
# uvicorn main:app --reload
# แล้วเข้า http://localhost:8000/users/me

โคตรคลีนเลยใช่ไหม? ฟังก์ชัน get_current_user_id จะถูกเรียกก่อนที่ read_current_user จะรัน ถ้ามัน return ค่ามาอะไร ก็จะถูกส่งเป็น user_id เข้าไปในฟังก์ชัน read_current_user ทันที

ระวังเรื่อง Blocking I/O ใน Async Code

อันนี้โคตรสำคัญเลยนะ เคยเจอไหม รันโปรเจกต์ FastAPI แล้วมันชอบค้างๆ หรือรู้สึกว่ามันช้าๆ ทั้งๆ ที่เขียน async def เต็มไปหมด? บางทีมันก็ไม่ได้ช่วยอะไรนะ ถ้าข้างในคุณยังไปเรียกไลบรารีที่มันเป็น blocking I/O (เช่น requests แบบปกติ, หรือ Database Driver บางตัวที่ไม่ได้รองรับ async โดยตรง) แบบนี้อะ:

import time
import requests # อันนี้เป็น sync library

# ...ใน main.py ต่อจากโค้ดข้างบน

@app.get("/blocking_example")
async def blocking_example():
    print("เริ่ม blocking call")
    # เนี่ยแหละตัวดี! มันจะบล็อก event loop ทั้งหมดเลยนะ
    time.sleep(5) # สมมติว่านี่คือการเรียก API ที่ใช้เวลานานมากๆ
    # response = requests.get("http://some-slow-api.com") # ถ้าใช้ requests ตรงๆ ใน async function ก็จะ block เหมือนกันถ้าไม่ใช้ run_in_threadpool
    print("จบ blocking call")
    return {"message": "ทำเสร็จแล้วนะ แต่รอนานหน่อย"}

# ลองรันแล้วลองเปิดแท็บ /blocking_example สองแท็บพร้อมกันดูดิ
# แท็บที่สองจะรอจนแท็บแรกเสร็จก่อนถึงจะเริ่ม process

โค้ดมันก็รันไปนะ แต่เส้นทางอื่นแม่งก็ต้องรอด้วย ถ้าเจอไอ้ blocking function นี่แหละ น่าหงุดหงิดชะมัด! ทางแก้คือถ้าต้องทำอะไรที่ block นานๆ ให้ย้ายไปรันใน ThreadPoolExecutor ของ Starlette (ซึ่ง FastAPI ก็ใช้) ด้วย run_in_threadpool หรือใช้ไลบรารีที่เป็น async โดยตรงอย่าง httpx แทน requests หรือ asyncpg แทน psycopg2 อะไรแบบนั้น

สรุปนะ

โดยรวมนะ ถ้าจะทำ API ใหม่ๆ แล้วอยากได้ที่มันเร็ว เขียนง่าย (ด้วย Type Hint) เทสสะดวก (ด้วย DI) แถมมีเอกสารให้ฟรีๆ ด้วย FastAPI คือคำตอบอะ เชื่อดิ ลองแล้วจะติดใจ! มันทำให้การเขียน API สนุกขึ้นเยอะเลยนะ ไม่ใช่เรื่องน่าปวดหัวอีกต่อไป

ไปลองเล่นดู! แล้วคุณจะรู้สึกว่ามัน 'ว้าว!' จริงๆ

Read more

PSG vs Monaco: ศึก 100 นัดเดือด ลีกเอิง และบทเรียนที่ปาร์ค เดส์ แพร็งซ์

PSG vs Monaco: ศึก 100 นัดเดือด ลีกเอิง และบทเรียนที่ปาร์ค เดส์ แพร็งซ์

สรุปผลและวิเคราะห์เกมเดือด PSG พบ Monaco ในลีกเอิงนัดที่ 25 ซึ่งเป็นการพบกันครั้งที่ 100 ในประวัติศาสตร์ลีก ความพ่ายแพ้ 1-3 คาบ้านของ PSG และบทบาทของ Akliouche พร้อมผลกระทบต่อเส้นทางแชมเปี้ยนส์ลีก

By ทีมงาน devdog
บาเยิร์นผงาดไร้เคน! ถล่มกลัดบัค 4-1 โชว์ความลึกของทีมก่อนลุยศึก UCL

บาเยิร์นผงาดไร้เคน! ถล่มกลัดบัค 4-1 โชว์ความลึกของทีมก่อนลุยศึก UCL

บาเยิร์น มิวนิค โชว์ฟอร์มแกร่ง แม้ไม่มีแฮร์รี่ เคน ถล่ม โบรุสเซีย มึนเชนกลัดบัค 4-1 ก่อนเตรียมลุยศึกแชมเปียนส์ลีกกับอตาลันต้า!

By ทีมงาน devdog
PSG: มหาอำนาจลูกหนังฝรั่งเศส กับศึกดวลเดือดโมนาโก และเป้าหมายสู่บัลลังก์ยุโรป

PSG: มหาอำนาจลูกหนังฝรั่งเศส กับศึกดวลเดือดโมนาโก และเป้าหมายสู่บัลลังก์ยุโรป

เจาะลึกเส้นทาง PSG สู่มหาอำนาจลูกหนัง วิเคราะห์สถานการณ์ลีกเอิง เตรียมพร้อมศึกใหญ่กับโมนาโก พร้อมความมุ่งมั่นสู่แชมป์ยุโรป

By ทีมงาน devdog
ลาลีกา: มนต์เสน่ห์ฟุตบอลสเปน, นวัตกรรมเรโทร, และบิ๊กแมตช์แห่งอนาคต

ลาลีกา: มนต์เสน่ห์ฟุตบอลสเปน, นวัตกรรมเรโทร, และบิ๊กแมตช์แห่งอนาคต

สำรวจลาลีกา ฟุตบอลสเปนอันทรงเสน่ห์ พร้อมไฮไลต์บิ๊กแมตช์ 2025/26 นวัตกรรมสัปดาห์เรโทร และบทบาทต่อวัฒนธรรมและเศรษฐกิจ.

By ทีมงาน devdog