Episode ini menyatukan model, skema, dan validasi: mendesain skema database dengan Prisma, memvalidasi input request dengan Zod, serta menerapkan validasi di route Express sebelum data menyentuh database.

Data yang masuk ke aplikasi datang dari dunia luar — form, API pihak ketiga, permintaan pengguna — dan tidak pernah bisa dipercaya begitu saja. Lapisan yang menangani hal ini adalah validasi: memeriksa data sebelum data itu diproses atau disimpan.
Episode 15 merangkai tiga konsep yang saling melengkapi: model untuk struktur data di database, skema sebagai deskripsi formal struktur itu, dan validasi sebagai pemeriksaan runtime terhadap data yang masuk. Kalian akan memakai Prisma untuk model dan Zod untuk validasi input di route Express.
Model database yang baik menentukan kualitas aplikasi jangka panjang. Skema Prisma dari episode 14 bisa diperluas dengan relasi — misalnya satu pengguna punya banyak artikel:
model Pengguna {
id Int @id @default(autoincrement())
email String @unique
nama String
artikel Artikel[]
}
model Artikel {
id Int @id @default(autoincrement())
judul String
isi String
penulisId Int
penulis Pengguna @relation(fields: [penulisId], references: [id])
}Deklarasi artikel Artikel[] di model Pengguna dan penulis Pengguna @relation(...) di model Artikel membentuk relasi satu-ke-banyak. Skema ini lalu diterjemahkan menjadi tabel oleh migration. Desain yang baik mencegah data duplikat dan relasi yang menggantung.
Saat mendesain skema, tanyakan: apa entitas inti, apa relasinya, dan field apa yang wajib ada? Tambahkan index untuk kolom yang sering dipakai sebagai filter. Skema yang terlalu kaku sulit diubah, tapi skema yang terlalu longgar menimbulkan data berantakan — keseimbangan adalah kuncinya.
Zod adalah library validasi yang populer di ekosistem TypeScript dan Node.js. Kalian mendeskripsikan bentuk data yang diharapkan, dan Zod memeriksa data nyata terhadap deskripsi itu:
npm install zodnpm install zod menambahkan validator dengan inferensi tipe otomatis. Zod terintegrasi mulus dengan Prisma dan TypeScript, tapi juga bekerja tanpa TypeScript.
import { z } from "zod";
const skemaPengguna = z.object({
nama: z.string().min(3).max(100),
email: z.string().email(),
umur: z.number().int().positive().optional(),
});z.object({...}) mendeskripsikan objek yang diharapkan: nama wajib string dengan panjang 3 sampai 100, email harus berformat email, dan umur opsional berupa bilangan bulat positif. skemaPengguna.parse(data) melempar error jika data melanggar aturan, sedangkan skemaPengguna.safeParse(data) mengembalikan hasil tanpa melempar.
Gabungkan skema Zod dengan route Express lewat middleware:
app.post("/api/pengguna", (req, res) => {
const hasil = skemaPengguna.safeParse(req.body);
if (!hasil.success) {
return res.status(400).json({
error: "Data tidak valid",
detail: hasil.error.issues,
});
}
const pengguna = await prisma.pengguna.create({
data: hasil.data,
});
res.status(201).json(pengguna);
});skemaPengguna.safeParse(req.body) memeriksa body request. Jika gagal, response 400 membawa detail isu validasi; jika berhasil, data bersih di hasil.data yang diteruskan ke Prisma. Pola ini menjamin data yang sampai ke database sudah terbentuk sesuai skema.
Urutan pertahanan itu penting: validasi input di tepi aplikasi, bukan di dekat database. Dengan validasi di route, request yang buruk ditolak lebih awal tanpa membuang resource database. Prisma sendiri juga memvalidasi saat create, tapi validasi Zod lebih awal berarti error yang lebih jelas dan terkendali bagi konsumen API.
Model Prisma dan skema Zod menggambarkan data yang sama dari dua sisi: satu untuk persistence, satu untuk boundary API. Idealnya keduanya selaras — field yang wajib di Zod ada di model, tipe yang dipakai cocok, dan relasi yang diizinkan tidak melanggar aturan database.
Menjaga keduanya sinkron butuh disiplin, terutama saat tim berkembang. Beberapa project menurunkan skema Zod langsung dari model Prisma untuk menghindari duplikasi, sementara project lain menerima duplikasi demi kejelasan. Pilih pendekatan yang bisa dipertahankan tim kalian.
Inti yang harus dibawa pulang:
z.object.safeParse mengembalikan hasil tanpa melempar error.Di episode 16 selanjutnya kita akan membahas caching, session, dan state server-side — perbedaan aplikasi stateless dan stateful, session dengan express-session, caching dengan Redis, serta pengaturan header cache untuk respons HTTP. Kalian akan belajar membuat API yang lebih cepat dan hemat resource.