Belajar FastAPI - Pydantic Models & Validation
Episode 5 of 28

Belajar FastAPI - Pydantic Models & Validation

Memahami Pydantic models untuk validasi request dan response: model sederhana dan nested, constraint dengan Field, validator antar field dengan field_validator dan model_validator, hingga cara kerja mode validasi Pydantic 2.x.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Setelah di episode 4 kita menguasai routing dan parameter, sekarang kita masuk ke jantung FastAPI: Pydantic models. Di episode 2 kita sudah melihat bahwa semua request/response melewati Pydantic — sekarang saatnya mempelajari cara mendefinisikan schema yang benar.

Mengapa episode ini penting? Karena di sinilah kualitas API kalian ditentukan. API yang validasinya longgar akan menerima data sampah masuk ke database, sementara API yang validasinya berlebihan akan menyulitkan klien. Pydantic memberi kalian alat untuk menemukan titik tengah yang tepat — dan FastAPI menjadikannya bagian dari OpenAPI secara otomatis.

Model Pertama

Pydantic model didefinisikan sebagai class Python yang mewarisi BaseModel. Di episode 5-8 kita memakai file schemas.py terpisah agar rapi:

Pythonapp/schemas.py
from pydantic import BaseModel, Field
 
 
class ItemCreate(BaseModel):
    name: str = Field(min_length=1, max_length=100)
    price: float = Field(gt=0, le=1_000_000)
    is_offer: bool = False
 
 
class Item(ItemCreate):
    id: int

Dua model di atas memperlihatkan pola penting:

  1. ItemCreate — schema untuk request body: name wajib (1-100 karakter), price wajib (harus 0 sampai 1.000.000), is_offer opsional berdefault False.
  2. Item — schema response: mewarisi semua field ItemCreate dan menambahkan id. Pewarisan model adalah cara idiomatis menghindari duplikasi antara input dan output.

Field(...) menambahkan constraint. Singkatan yang perlu dihafal: gt (greater than), ge (greater or equal), lt, le, min_length, max_length, pattern.

Memakai Model di Endpoint

Pythonapp/main.py - endpoint dengan body model
from fastapi import FastAPI
from app.schemas import Item, ItemCreate
 
app = FastAPI()
 
 
@app.post("/items/")
def create_item(item: ItemCreate) -> Item:
    item_id = 1
    return Item(id=item_id, **item.model_dump())

item: ItemCreate memberitahu FastAPI: request body harus sesuai ItemCreate. FastAPI lalu:

  • Memvalidasi JSON masuk terhadap model → error 422 dengan detail per-field jika tidak cocok.
  • Menyediakan objek ItemCreate yang sudah bersih ke handler.
  • Memvalidasi return value terhadap Item (response model) sebelum serialisasi.

model_dump() mengubah model menjadi dict (metode ini menggantikan dict() yang deprecated di Pydantic 2.x) — lalu kita bangun Item dengan id dari database.

Note

Perhatikan bahwa validasi dua arah: Pydantic tidak hanya memvalidasi request masuk, tetapi juga memvalidasi data yang kalian kembalikan. Ini mencegah bocornya field internal — misalnya password — ke response. Episode 7 membahas response model secara khusus.

Nested Models

API dunia nyata jarang datar. Pydantic mendukung model bertingkat secara native:

Pythonapp/schemas.py - nested models
from pydantic import BaseModel, Field
 
 
class Tag(BaseModel):
    name: str = Field(min_length=1, max_length=20)
 
 
class Order(BaseModel):
    id: int
    customer: str
    items: list[Item]
    tags: list[Tag] = []
    metadata_: dict[str, str] = {}

items: list[Item] — list berisi model lain — divalidasi elemen per elemen. JSON masuk:

Request body order
{
  "id": 10,
  "customer": "Budi",
  "items": [
    {"id": 1, "name": "Keyboard", "price": 500000}
  ]
}

divalidasi penuh: setiap item dicek terhadap Item, dan seluruh struktur wajib lengkap. Nested models ini yang akan dipakai terus menerus mulai episode 9 saat kita berhadapan dengan ORM.

Field Validator

Terkadang constraint sederhana tidak cukup — butuh logika validasi. Pydantic 2.x menyediakan validator per-field:

Pythonapp/schemas.py - field_validator
from pydantic import BaseModel, field_validator
 
 
class UserCreate(BaseModel):
    username: str
    email: str
 
    @field_validator("username")
    @classmethod
    def username_berlaku(cls, v: str) -> str:
        if not v.replace("_", "").isalnum():
            raise ValueError("username hanya boleh alfanumerik dan underscore")
        return v.lower()

Dua hal yang wajib diingat soal validator Pydantic 2.x:

  • Ditulis sebagai classmethod dan di-dekorasi @classmethod (urutan dekorator: @field_validator di luar, @classmethod di dalam).
  • Gagal dengan raise ValueError(...) → Pydantic mengubahnya menjadi error validasi yang muncul sebagai detail 422.

Perhatikan bahwa validator menghasilkan nilai baru (di sini v.lower()): pola normalisasi di dalam validator adalah teknik yang sangat berguna.

Model Validator: Validasi Antar Field

Kadang aturan validasi melibatkan beberapa field sekaligus. Contoh klasik: password dan konfirmasinya:

Pythonapp/schemas.py - model_validator
from pydantic import BaseModel, model_validator
 
 
class Signup(BaseModel):
    password: str
    confirm: str
 
    @model_validator(mode="after")
    @classmethod
    def password_cocok(cls, data: "Signup") -> "Signup":
        if data.password != data.confirm:
            raise ValueError("password dan confirm harus sama")
        return data

mode="after" berarti validator berjalan setelah semua field divalidasi — jadi data sudah berupa objek Signup lengkap. Pola before (sebelum parsing) jarang dibutuhkan pemula; fokus pada after.

Tip

Aturan praktis: gunakan @field_validator untuk aturan satu field, dan @model_validator(mode="after") untuk aturan yang melihat beberapa field. Ini menjaga validator tetap kecil dan mudah diuji — sejalan dengan filosofi FastAPI yang high signal.

Validasi Request vs Schema: Kenapa Pydantic Penting

Tanpa Pydantic (API naif)Dengan Pydantic (API FastAPI)
price bisa string "banyak"Otomatis ditolak, detail field di 422
name bisa 10.000 karaktermax_length membatasi
Data sampah masuk ke databaseData bersih dan sudah dikonversi tipe
Tidak ada dokumentasi schemaSchema otomatis ada di /docs

Inilah kenapa "validasi di boundary" adalah best practice keamanan: data yang masuk API adalah data asing, dan setiap asumsi soal tipe harus dibuktikan oleh validator — bukan dipercaya begitu saja.

Common Pitfalls

PitfallSolusi
Memakai dict() Pydantic (deprecated)Gunakan model_dump()
Lupa @classmethod pada validatorError deklarasi saat import
Menulis logika bisnis dalam validatorValidator untuk kebenaran data; logika bisnis di service layer
Mengganti nama field jadi keyword PythonTambahkan underscore: metadata_

Penutup

Inti yang harus dibawa pulang:

  • Pydantic model = class turunan BaseModel; Field untuk constraint.
  • Pewarisan model (Item(ItemCreate)) menghindari duplikasi schema.
  • Nested models divalidasi rekursif — list[Item], dict[str, str].
  • @field_validator untuk aturan satu field; @model_validator(mode="after") untuk lintas field.
  • Validasi berjalan dua arah: request masuk dan response keluar.

Di episode 6 selanjutnya kita akan membahas request body & forms — mengombinasikan body model dengan path/query params, memakai embed=True untuk struktur JSON tertentu, serta menangani data application/x-www-form-urlencoded dengan Form. Pastikan skema dari episode ini sudah dicoba, karena episode 6 membangun di atasnya!

Belajar FastAPI - Pydantic Models & Validation | Belajar FastAPI