Home > Blog > tech

สอน Python FastAPI ฉบับสมบูรณ์ 2026: สร้าง REST API แบบมืออาชีพ

Python FastAPI Web Development 2026
2026-04-07 | tech | 3200 words

FastAPI เป็นเว็บเฟรมเวิร์กสำหรับ Python ที่ได้รับความนิยมเพิ่มขึ้นอย่างรวดเร็วในช่วง 2-3 ปีที่ผ่านมา และในปี 2026 ก็กลายเป็นหนึ่งในตัวเลือกอันดับต้นๆ สำหรับการสร้าง REST API ด้วยภาษา Python ด้วยความเร็วในการประมวลผลที่ใกล้เคียง Node.js และ Go รองรับ async/await อย่างเต็มรูปแบบ พร้อมระบบ type hints ที่ช่วยให้โค้ดปลอดภัยและดูแลรักษาง่าย

บทความนี้จะพาคุณไปตั้งแต่เริ่มต้นจนถึงการ deploy ครอบคลุมทุกหัวข้อสำคัญที่นักพัฒนาควรรู้ ไม่ว่าจะเป็น path parameters, request body ด้วย Pydantic, การเชื่อมต่อฐานข้อมูลด้วย SQLAlchemy, ระบบ authentication ด้วย JWT และแนวปฏิบัติที่ดีที่สุดสำหรับปี 2026

FastAPI คืออะไร?

FastAPI เป็น modern web framework สำหรับ Python 3.7+ ที่สร้างขึ้นโดย Sebastián Ramírez โดยใช้ประโยชน์จาก Python type hints อย่างเต็มที่ ชื่อ "Fast" มาจาก 2 ความหมาย คือ เร็วในการรัน (performance) และเร็วในการเขียนโค้ด (developer productivity)

สิ่งที่ทำให้ FastAPI โดดเด่นเหนือเฟรมเวิร์กอื่นคือ:

ทำไมต้อง FastAPI ในปี 2026? จากสถิติของ Python Developers Survey ล่าสุด FastAPI แซง Flask เป็นเฟรมเวิร์กยอดนิยมอันดับ 2 รองจาก Django แล้ว และเป็นอันดับ 1 สำหรับงาน API โดยเฉพาะ

การติดตั้ง FastAPI

การเริ่มต้นกับ FastAPI ง่ายมาก เพียงติดตั้ง 2 แพ็กเกจหลัก ได้แก่ fastapi ตัวเฟรมเวิร์ก และ uvicorn ตัว ASGI server สำหรับรันแอปพลิเคชัน

สร้าง Virtual Environment

# สร้างโฟลเดอร์โปรเจกต์
mkdir fastapi-project && cd fastapi-project

# สร้าง virtual environment
python -m venv venv

# activate (Linux/Mac)
source venv/bin/activate

# activate (Windows)
venv\Scripts\activate

ติดตั้ง FastAPI และ Uvicorn

# ติดตั้งแบบเต็ม (แนะนำ)
pip install "fastapi[standard]"

# หรือติดตั้งแยก
pip install fastapi uvicorn[standard]

# ตรวจสอบเวอร์ชัน
python -c "import fastapi; print(fastapi.__version__)"
Tip: การใช้ fastapi[standard] จะติดตั้ง dependencies ที่จำเป็นทั้งหมดรวมถึง uvicorn, pydantic, python-multipart และ jinja2

สร้าง API ตัวแรก (Hello World)

มาเริ่มสร้าง API ตัวแรกกัน สร้างไฟล์ main.py ดังนี้:

from fastapi import FastAPI

app = FastAPI(
    title="My First API",
    description="API ตัวแรกของฉัน",
    version="1.0.0"
)

@app.get("/")
async def root():
    return {"message": "สวัสดี FastAPI!", "status": "ok"}

@app.get("/health")
async def health_check():
    return {"status": "healthy", "version": "1.0.0"}

รันเซิร์ฟเวอร์ด้วยคำสั่ง:

uvicorn main:app --reload --host 0.0.0.0 --port 8000

เปิดเบราว์เซอร์ไปที่ http://localhost:8000 จะเห็น JSON response และไปที่ http://localhost:8000/docs จะเห็น Swagger UI ที่สร้างอัตโนมัติ พร้อมให้ทดสอบ API ได้เลย

Path Parameters และ Query Parameters

FastAPI ทำให้การรับ parameters จาก URL ง่ายและปลอดภัยด้วย type hints

Path Parameters

from fastapi import FastAPI, HTTPException

app = FastAPI()

# Database จำลอง
users_db = {
    1: {"id": 1, "name": "สมชาย", "email": "somchai@example.com"},
    2: {"id": 2, "name": "สมหญิง", "email": "somying@example.com"}
}

@app.get("/users/{user_id}")
async def get_user(user_id: int):
    if user_id not in users_db:
        raise HTTPException(status_code=404, detail="ไม่พบผู้ใช้")
    return users_db[user_id]

@app.get("/users/{user_id}/posts/{post_id}")
async def get_user_post(user_id: int, post_id: int):
    return {"user_id": user_id, "post_id": post_id}

FastAPI จะแปลง user_id เป็น int ให้อัตโนมัติ ถ้าส่งค่าที่ไม่ใช่ตัวเลขมา จะได้ 422 Validation Error พร้อมข้อความอธิบายที่ชัดเจน

Query Parameters

from typing import Optional

@app.get("/products")
async def get_products(
    category: Optional[str] = None,
    min_price: float = 0,
    max_price: float = 999999,
    page: int = 1,
    limit: int = 20
):
    return {
        "category": category,
        "price_range": [min_price, max_price],
        "page": page,
        "limit": limit
    }

เรียกใช้ได้เช่น /products?category=electronics&min_price=100&page=2 ค่าที่ไม่ส่งมาจะใช้ค่า default ที่กำหนดไว้

Request Body กับ Pydantic Models

Pydantic เป็นหัวใจสำคัญของ FastAPI ทำหน้าที่ validate และ serialize ข้อมูลที่รับเข้ามา ทำให้ API ปลอดภัยจากข้อมูลที่ไม่ถูกต้องโดยอัตโนมัติ

from pydantic import BaseModel, Field, EmailStr
from typing import Optional
from datetime import datetime

class UserCreate(BaseModel):
    name: str = Field(..., min_length=2, max_length=100,
                      description="ชื่อผู้ใช้")
    email: EmailStr = Field(..., description="อีเมล")
    age: int = Field(..., ge=13, le=120,
                     description="อายุ (13-120)")
    bio: Optional[str] = Field(None, max_length=500)

class UserResponse(BaseModel):
    id: int
    name: str
    email: str
    age: int
    bio: Optional[str]
    created_at: datetime

    class Config:
        from_attributes = True  # Pydantic v2

@app.post("/users", response_model=UserResponse,
           status_code=201)
async def create_user(user: UserCreate):
    # Pydantic validate ข้อมูลให้อัตโนมัติ
    new_user = {
        "id": 3,
        "name": user.name,
        "email": user.email,
        "age": user.age,
        "bio": user.bio,
        "created_at": datetime.now()
    }
    return new_user

Pydantic v2 ที่ใช้ใน FastAPI 0.100+ มีการปรับปรุงประสิทธิภาพอย่างมาก เร็วขึ้น 5-50 เท่าเมื่อเทียบกับ v1 เนื่องจาก core ถูกเขียนใหม่ด้วย Rust

Nested Models และ Validation ขั้นสูง

from pydantic import BaseModel, field_validator
from typing import List

class Address(BaseModel):
    street: str
    city: str
    province: str
    postal_code: str

    @field_validator("postal_code")
    @classmethod
    def validate_postal(cls, v):
        if not v.isdigit() or len(v) != 5:
            raise ValueError("รหัสไปรษณีย์ต้องเป็นตัวเลข 5 หลัก")
        return v

class OrderItem(BaseModel):
    product_id: int
    quantity: int = Field(ge=1, le=100)
    price: float = Field(gt=0)

class Order(BaseModel):
    customer_name: str
    shipping_address: Address
    items: List[OrderItem] = Field(min_length=1)

    @property
    def total(self) -> float:
        return sum(i.price * i.quantity for i in self.items)

@app.post("/orders")
async def create_order(order: Order):
    return {
        "message": "สร้างออเดอร์สำเร็จ",
        "total": order.total,
        "items_count": len(order.items)
    }

เชื่อมต่อฐานข้อมูลด้วย SQLAlchemy

ในโปรเจกต์จริง คุณจะต้องเชื่อมต่อกับฐานข้อมูล SQLAlchemy เป็น ORM ยอดนิยมที่ทำงานร่วมกับ FastAPI ได้อย่างดีเยี่ยม รองรับทั้ง PostgreSQL, MySQL, SQLite และอื่นๆ

โครงสร้างโปรเจกต์

fastapi-project/
├── main.py
├── database.py
├── models.py
├── schemas.py
├── crud.py
├── routers/
│   ├── users.py
│   └── products.py
├── requirements.txt
└── .env

ตั้งค่า Database Connection

# database.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

SQLALCHEMY_DATABASE_URL = "postgresql://user:password@localhost/mydb"
# สำหรับ SQLite ใช้:
# SQLALCHEMY_DATABASE_URL = "sqlite:///./app.db"

engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal = sessionmaker(autocommit=False, autoflush=False,
                            bind=engine)
Base = declarative_base()

# Dependency สำหรับ inject DB session
def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

สร้าง Models

# models.py
from sqlalchemy import Column, Integer, String, Float,
    DateTime, ForeignKey
from sqlalchemy.orm import relationship
from datetime import datetime
from database import Base

class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True, index=True)
    name = Column(String(100), nullable=False)
    email = Column(String(255), unique=True, index=True)
    hashed_password = Column(String(255))
    created_at = Column(DateTime, default=datetime.utcnow)
    posts = relationship("Post", back_populates="author")

class Post(Base):
    __tablename__ = "posts"
    id = Column(Integer, primary_key=True, index=True)
    title = Column(String(200), nullable=False)
    content = Column(String, nullable=False)
    author_id = Column(Integer, ForeignKey("users.id"))
    created_at = Column(DateTime, default=datetime.utcnow)
    author = relationship("User", back_populates="posts")

CRUD Operations

# crud.py
from sqlalchemy.orm import Session
from models import User, Post
from schemas import UserCreate, PostCreate
from passlib.context import CryptContext

pwd_context = CryptContext(schemes=["bcrypt"])

def create_user(db: Session, user: UserCreate):
    hashed = pwd_context.hash(user.password)
    db_user = User(
        name=user.name,
        email=user.email,
        hashed_password=hashed
    )
    db.add(db_user)
    db.commit()
    db.refresh(db_user)
    return db_user

def get_users(db: Session, skip: int = 0, limit: int = 20):
    return db.query(User).offset(skip).limit(limit).all()

def get_user_by_email(db: Session, email: str):
    return db.query(User).filter(User.email == email).first()

ใช้ Dependency Injection ใน Router

# routers/users.py
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from database import get_db
import crud, schemas

router = APIRouter(prefix="/api/v1/users", tags=["users"])

@router.post("/", response_model=schemas.UserResponse,
              status_code=201)
def create_user(user: schemas.UserCreate,
                db: Session = Depends(get_db)):
    existing = crud.get_user_by_email(db, user.email)
    if existing:
        raise HTTPException(400, "อีเมลนี้ถูกใช้แล้ว")
    return crud.create_user(db, user)

@router.get("/", response_model=list[schemas.UserResponse])
def list_users(skip: int = 0, limit: int = 20,
               db: Session = Depends(get_db)):
    return crud.get_users(db, skip, limit)

ระบบ Authentication ด้วย JWT

การทำ authentication เป็นสิ่งจำเป็นสำหรับ API ที่ใช้งานจริง FastAPI มี security utilities ที่ช่วยให้ implement OAuth2 + JWT ได้ง่าย

# auth.py
from datetime import datetime, timedelta
from typing import Optional
from jose import JWTError, jwt
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer

SECRET_KEY = "your-secret-key-change-in-production"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

def create_access_token(data: dict,
                        expires_delta: Optional[timedelta] = None):
    to_encode = data.copy()
    expire = datetime.utcnow() + (
        expires_delta or timedelta(minutes=15)
    )
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

async def get_current_user(
    token: str = Depends(oauth2_scheme),
    db: Session = Depends(get_db)
):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="ไม่สามารถยืนยันตัวตนได้",
        headers={"WWW-Authenticate": "Bearer"}
    )
    try:
        payload = jwt.decode(token, SECRET_KEY,
                             algorithms=[ALGORITHM])
        email: str = payload.get("sub")
        if email is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception

    user = crud.get_user_by_email(db, email)
    if user is None:
        raise credentials_exception
    return user

# Login endpoint
@app.post("/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends(),
                db: Session = Depends(get_db)):
    user = authenticate_user(db, form_data.username,
                             form_data.password)
    if not user:
        raise HTTPException(400, "อีเมลหรือรหัสผ่านไม่ถูกต้อง")
    token = create_access_token(data={"sub": user.email})
    return {"access_token": token, "token_type": "bearer"}

# Protected endpoint
@app.get("/me")
async def read_me(current_user = Depends(get_current_user)):
    return current_user
ข้อควรระวัง: อย่าลืมเปลี่ยน SECRET_KEY เป็นค่าที่ปลอดภัยในระบบจริง ใช้ openssl rand -hex 32 สร้างได้ และเก็บใน environment variable เสมอ

Middleware และ Error Handling

Middleware ช่วยให้คุณเพิ่มฟังก์ชันที่ทำงานทุกครั้งที่มี request เข้ามา เช่น logging, CORS, rate limiting

from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
import time
import logging

app = FastAPI()

# CORS Middleware
app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://yourfrontend.com"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"]
)

# Custom Logging Middleware
@app.middleware("http")
async def log_requests(request: Request, call_next):
    start = time.time()
    response = await call_next(request)
    duration = time.time() - start
    logging.info(
        f"{request.method} {request.url.path} "
        f"{response.status_code} {duration:.3f}s"
    )
    return response

# Global Exception Handler
@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc):
    logging.error(f"Unhandled error: {exc}")
    return JSONResponse(
        status_code=500,
        content={"detail": "เกิดข้อผิดพลาดภายในเซิร์ฟเวอร์"}
    )

Background Tasks และ WebSocket

FastAPI รองรับ background tasks สำหรับงานที่ใช้เวลานานโดยไม่ต้องให้ client รอ และ WebSocket สำหรับการสื่อสารแบบ real-time

Background Tasks

from fastapi import BackgroundTasks

def send_email_notification(email: str, message: str):
    # ส่งอีเมล (ใช้เวลานาน)
    import smtplib
    # ... logic ส่งอีเมล ...

@app.post("/subscribe")
async def subscribe(
    email: str,
    background_tasks: BackgroundTasks
):
    background_tasks.add_task(
        send_email_notification,
        email,
        "ยินดีต้อนรับสู่ระบบ!"
    )
    return {"message": "สมัครสำเร็จ อีเมลยืนยันกำลังส่ง"}

WebSocket

from fastapi import WebSocket, WebSocketDisconnect

connected_clients: list[WebSocket] = []

@app.websocket("/ws/chat")
async def websocket_chat(websocket: WebSocket):
    await websocket.accept()
    connected_clients.append(websocket)
    try:
        while True:
            data = await websocket.receive_text()
            # Broadcast ไปทุก client
            for client in connected_clients:
                await client.send_text(
                    f"ข้อความใหม่: {data}"
                )
    except WebSocketDisconnect:
        connected_clients.remove(websocket)

Testing API ด้วย pytest

การเขียน test เป็นสิ่งสำคัญสำหรับ API ที่ใช้งานจริง FastAPI มี TestClient ที่ทำให้เขียน test ได้ง่าย

# test_main.py
from fastapi.testclient import TestClient
from main import app

client = TestClient(app)

def test_read_root():
    response = client.get("/")
    assert response.status_code == 200
    assert "message" in response.json()

def test_create_user():
    response = client.post("/users", json={
        "name": "ทดสอบ",
        "email": "test@example.com",
        "age": 25
    })
    assert response.status_code == 201
    data = response.json()
    assert data["name"] == "ทดสอบ"

def test_create_user_invalid_email():
    response = client.post("/users", json={
        "name": "ทดสอบ",
        "email": "invalid-email",
        "age": 25
    })
    assert response.status_code == 422

def test_get_user_not_found():
    response = client.get("/users/99999")
    assert response.status_code == 404

# รัน: pytest test_main.py -v

การ Deploy FastAPI สู่ Production

เมื่อพัฒนาเสร็จแล้ว ขั้นตอนสุดท้ายคือการ deploy สู่ production มีหลายทางเลือก:

วิธีที่ 1: Docker (แนะนำ)

# Dockerfile
FROM python:3.12-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .

EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0",
     "--port", "8000", "--workers", "4"]
# docker-compose.yml
services:
  api:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://user:pass@db/mydb
      - SECRET_KEY=${SECRET_KEY}
    depends_on:
      - db
    restart: unless-stopped

  db:
    image: postgres:16
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=mydb
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=pass

volumes:
  pgdata:

วิธีที่ 2: Gunicorn + Uvicorn Workers

# สำหรับ production บน Linux
pip install gunicorn

gunicorn main:app \
  --workers 4 \
  --worker-class uvicorn.workers.UvicornWorker \
  --bind 0.0.0.0:8000 \
  --access-logfile - \
  --error-logfile -

วิธีที่ 3: Cloud Platforms

FastAPI deploy ได้ง่ายบนหลาย platform:

Platformวิธี Deployราคาเริ่มต้น
Railwayเชื่อม GitHub repo อัตโนมัติ$5/เดือน
Renderเชื่อม GitHub + Dockerfileฟรี (limited)
Fly.ioCLI deploy + Dockerfileฟรี (limited)
AWS LambdaMangum adapterPay-per-use
Google Cloud RunContainer-basedPay-per-use
DigitalOcean Appเชื่อม GitHub$5/เดือน
สำหรับมือใหม่: แนะนำ Railway หรือ Render เพราะ setup ง่ายที่สุด เพียงเชื่อม GitHub repo แล้ว deploy อัตโนมัติ สำหรับโปรเจกต์ขนาดใหญ่ ใช้ Docker + VPS จะยืดหยุ่นกว่า

เปรียบเทียบ FastAPI vs Flask vs Django

เลือกเฟรมเวิร์กที่เหมาะกับงานของคุณ:

คุณสมบัติFastAPIFlaskDjango
ประเภทASGI (async)WSGI (sync)WSGI (sync)
Performanceสูงมากปานกลางปานกลาง
Learning Curveง่าย-ปานกลางง่ายปานกลาง-ยาก
Auto Docsมี (Swagger + ReDoc)ไม่มี (ต้องเพิ่ม)ไม่มี (ต้องเพิ่ม)
Data ValidationPydantic (built-in)ไม่มีForms/Serializers
ORMไม่มี (ใช้ SQLAlchemy)ไม่มี (ใช้ SQLAlchemy)Django ORM
Admin Panelไม่มีไม่มีมี (built-in)
Async SupportNativeจำกัดจำกัด (ASGI)
เหมาะกับAPI, MicroservicesAPI ขนาดเล็ก, PrototypeFull-stack web app

สรุป: ถ้าสร้าง REST API โดยเฉพาะ ให้เลือก FastAPI ถ้าต้องการ full-stack web app พร้อม admin panel ให้เลือก Django ส่วน Flask เหมาะกับ prototype ขนาดเล็กหรือเมื่อต้องการความยืดหยุ่นสูงสุด

Best Practices สำหรับ FastAPI ในปี 2026

แนวปฏิบัติที่ดีที่จะช่วยให้โปรเจกต์ของคุณดูแลรักษาได้ง่ายและ scale ได้ดี:

1. จัดโครงสร้างโปรเจกต์ให้เป็นระบบ

ใช้ APIRouter แบ่ง endpoint ตามหมวดหมู่ แยก models, schemas, crud ออกจากกัน อย่าเขียนทุกอย่างใน main.py ไฟล์เดียว

2. ใช้ Pydantic Settings สำหรับ Configuration

from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    database_url: str
    secret_key: str
    debug: bool = False
    api_prefix: str = "/api/v1"

    class Config:
        env_file = ".env"

settings = Settings()

3. ใช้ Alembic สำหรับ Database Migration

# ติดตั้งและเริ่มต้น
pip install alembic
alembic init alembic

# สร้าง migration
alembic revision --autogenerate -m "add users table"

# รัน migration
alembic upgrade head

4. ใช้ Dependency Injection อย่างเต็มที่

FastAPI มีระบบ DI ที่ทรงพลัง ใช้มันสำหรับ database sessions, authentication, permissions, caching และ shared resources ทั้งหมด

5. เขียน Test เสมอ

ใช้ pytest + httpx สำหรับ async testing ตั้ง CI/CD ให้รัน test อัตโนมัติทุกครั้งที่ push โค้ด

6. ใช้ Logging ที่เหมาะสม

ใช้ structlog หรือ loguru แทน print() สำหรับ production ตั้ง log level ให้เหมาะสม (INFO สำหรับ production, DEBUG สำหรับ development)

7. Rate Limiting และ Security

# ใช้ slowapi สำหรับ rate limiting
from slowapi import Limiter
from slowapi.util import get_remote_address

limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter

@app.get("/api/data")
@limiter.limit("100/minute")
async def get_data(request: Request):
    return {"data": "limited"}

8. API Versioning

ใช้ prefix ใน URL เช่น /api/v1/ และ /api/v2/ เพื่อให้สามารถอัปเดต API ได้โดยไม่ break client เดิม

9. ใช้ async อย่างถูกต้อง

ถ้าฟังก์ชันไม่มี I/O operation ที่เป็น async (เช่น database query, HTTP request) ไม่จำเป็นต้องใช้ async def ใช้ def ธรรมดาก็ได้ FastAPI จะรันใน thread pool ให้อัตโนมัติ

10. Documentation ที่ดี

เพิ่ม description, examples, tags ใน endpoint เพื่อให้ Swagger UI แสดงข้อมูลที่ครบถ้วน ทีมงานจะขอบคุณ

สรุป

FastAPI เป็นเฟรมเวิร์กที่ยอดเยี่ยมสำหรับการสร้าง REST API ด้วย Python ในปี 2026 ด้วยประสิทธิภาพสูง ระบบ type safety ที่แข็งแกร่ง auto documentation ที่สะดวก และ ecosystem ที่สมบูรณ์ ไม่ว่าจะเป็นมือใหม่หรือมือเก๋า FastAPI ก็เป็นทางเลือกที่คุ้มค่าแก่การเรียนรู้และใช้งาน

สิ่งที่เราได้เรียนรู้ในบทความนี้:

เริ่มต้นเขียน FastAPI วันนี้ แล้วคุณจะพบว่าการสร้าง API ด้วย Python ไม่เคยง่ายและสนุกขนาดนี้มาก่อน


Back to Blog | iCafe Forex | SiamLanCard | Siam2R