Pydantic Models
Schemas: Zod / interfaces → Pydantic BaseModel
หัวข้อที่มีชื่อว่า “Schemas: Zod / interfaces → Pydantic BaseModel”ใน TypeScript คุณอธิบายรูปร่าง request body ด้วย interface หรือ Zod schema ใน FastAPI คุณอธิบายด้วย subclass ของ Pydantic BaseModel ส่ง class นั้นเป็น type hint บน argument ของ route function และ FastAPI จะ parse และ validate request body อัตโนมัติ
// TypeScript — Zod schema + inferred typeimport { z } from 'zod';
const CreateItemSchema = z.object({ name: z.string().min(1), price: z.number().positive(), inStock: z.boolean().default(true), tags: z.array(z.string()).default([]),});
type CreateItem = z.infer<typeof CreateItemSchema>;
// NestJS DTO with class-validatorexport class CreateItemDto { @IsString() @MinLength(1) name: string; @IsNumber() @IsPositive() price: number; @IsBoolean() @IsOptional() inStock?: boolean = true;}# FastAPI — Pydantic BaseModelfrom pydantic import BaseModelfrom typing import Optional, List
class CreateItem(BaseModel): name: str price: float in_stock: bool = True tags: List[str] = []
# ใช้ใน route — FastAPI parse + validate อัตโนมัติfrom fastapi import FastAPIapp = FastAPI()
@app.post("/items", status_code=201)async def create_item(item: CreateItem): return item # Pydantic serialize กลับเป็น JSONNested models
หัวข้อที่มีชื่อว่า “Nested models”Pydantic models รวมกันได้อย่างเป็นธรรมชาติ ฝัง model หนึ่งไว้ใน model อื่นเหมือน nested Zod objects
// Zod nested objectconst AddressSchema = z.object({ street: z.string(), city: z.string(), zip: z.string().length(5),});
const UserSchema = z.object({ name: z.string(), address: AddressSchema,});# Pydantic nested modelsfrom pydantic import BaseModel
class Address(BaseModel): street: str city: str zip_code: str
class User(BaseModel): name: str address: Address
# FastAPI จะ parse nested JSON นี้อัตโนมัติ:# { "name": "Alice", "address": { "street": "1 Main St", ... } }Response models — แยก input จาก output
หัวข้อที่มีชื่อว่า “Response models — แยก input จาก output”รูปแบบที่พบบ่อยคือมี model แยกกันสำหรับ input (สิ่งที่ client ส่งมา) และ output (สิ่งที่คุณส่งกลับ) Pydantic ทำให้ compose ง่ายมาก
// TypeScript — แยก input / output typesinterface CreateItemDto { name: string; price: number; }interface ItemResponse { id: number; name: string; price: number; createdAt: string; }# Pydantic — แยก input / output modelsfrom pydantic import BaseModelfrom datetime import datetime
class CreateItem(BaseModel): # Request body name: str price: float
class ItemResponse(BaseModel): # Response shape id: int name: str price: float created_at: datetime
# Route ใช้ response_model= เพื่อ filter + serializefrom fastapi import FastAPIapp = FastAPI()
@app.post("/items", response_model=ItemResponse, status_code=201)async def create_item(item: CreateItem): # ปกติจะบันทึกลง DB แล้ว return row return ItemResponse(id=1, name=item.name, price=item.price, created_at=datetime.utcnow())ลองเล่น — stdlib dataclasses เป็น runnable stand-in
หัวข้อที่มีชื่อว่า “ลองเล่น — stdlib dataclasses เป็น runnable stand-in”Pydantic ไม่สามารถรันใน browser ได้ dataclasses จาก standard library ให้รูปร่างเดียวกัน (typed fields, defaults, auto __init__) โดยไม่มี validation เพื่อให้สำรวจแนวคิดได้:
from dataclasses import dataclass, field, asdictfrom typing import Optional, Listimport json
@dataclassclass CreateItem: name: str price: float in_stock: bool = True tags: List[str] = field(default_factory=list) description: Optional[str] = None
# สร้าง instance — รู้สึกเหมือน BaseModel(...)item = CreateItem(name="Widget", price=9.99, tags=["sale", "new"])print("item:", item)
# Serialize เป็น dict (เหมือน .model_dump())data = asdict(item)print("dict :", data)
# Serialize เป็น JSONprint("json :", json.dumps(data, indent=2))
# Nested dataclass@dataclassclass OrderLine: item: CreateItem quantity: int
line = OrderLine(item=item, quantity=3)print("\nnested:", asdict(line))Loading Python runtime (first run only)…