Bayangkan kita punya fungsi untuk memproses data registrasi pengguna yang datang dari sebuah form atau API. Tanpa library validasi, kodenya mungkin akan seperti ini:
// validasi-manual.js
function prosesRegistrasi(data) {
// Validasi manual yang panjang dan rawan kesalahan
if (!data) {
console.error("Error: Data tidak ditemukan!");
return;
}
if (typeof data.username !== 'string' || data.username.length < 3) {
console.error("Error: Username minimal 3 karakter.");
return;
}
if (typeof data.email !== 'string' || !data.email.includes('@')) {
console.error("Error: Format email tidak valid.");
return;
}
if (typeof data.age !== 'number' || data.age < 18) {
console.error("Error: Anda harus berusia minimal 18 tahun.");
return;
}
// Jika semua validasi lolos...
console.log("Registrasi berhasil untuk:", data.username);
// ...lanjutkan proses ke database
}
// Kasus sukses
prosesRegistrasi({ username: 'hadie', email: '[email protected]', age: 30 });
// Kasus gagal (mudah terjadi error)
prosesRegistrasi({ username: 'al', email: '[email protected]', age: 25 }); // Username terlalu pendek
prosesRegistrasi({ username: 'fathoni', email: 'fathoni-mail.com', age: 22 }); // Email tidak valid
Masalah yang terlihat:
Kode Bercabang dan Rumit: Penuh dengan
if-else
yang sulit dibaca.Rawan Kesalahan: Sangat mudah untuk melewatkan satu kasus validasi.
Tidak Reusable: Jika butuh validasi yang sama di tempat lain, kita harus menyalin kode ini.
Tidak Ada Type Safety: Kita tidak tahu pasti “bentuk” data yang seharusnya. Apakah
age
itustring
ataunumber
?
Solusi: Zod - Satu Sumber Kebenaran
Zod adalah library validasi skema yang mengutamakan TypeScript (TypeScript-first).
Fungsi & Filosofi Utamanya:
Schema-First: Alih-alih menulis fungsi validasi, kita mendefinisikan sebuah “skema” atau “blueprint” dari data kita. Zod akan melakukan validasi berdasarkan skema ini.
Single Source of Truth: Skema ini menjadi satu-satunya sumber kebenaran tentang bagaimana bentuk data kita seharusnya. Ini bisa digunakan di frontend, backend, di mana pun.
Type Inference Otomatis: Ini adalah keajaiban terbesar Zod. Dari skema yang kita buat, Zod bisa secara otomatis menghasilkan tipe TypeScript. Kita tidak perlu lagi menulis
interface
atautype
secara manual!
Alternatif Lain
Sebelum kita menyelam lebih dalam, penting untuk tahu bahwa Zod bukan satu-satunya pemain. Alternatif populer lainnya adalah:
Yup: Sangat populer dan sering dipasangkan dengan Formik. Sedikit lebih tua dari Zod dan API-nya tidak se-elegan Zod untuk TypeScript.
Joi: Sangat kuat dan matang, sering digunakan di ekosistem Node.js untuk validasi di backend.
Kenapa kita memilih Zod? Sebenarnya bebas aja mau memilih yang mana. Tapi ini sebagai gambaran awal bahwa dengan library validasi yang ada, kita bisa hemat waktu untuk menghandle input sesuai ekspektasi kita.
Perbandingan: Fungsi yang Sama dengan Zod
Mari kita tulis ulang fungsi prosesRegistrasi
kita menggunakan Zod.
// validasi-dengan-zod.ts
import { z } from 'zod';
// 1. Definisikan skema sebagai satu sumber kebenaran
const userSchema = z.object({
username: z.string().min(3, { message: "Username minimal 3 karakter." }),
email: z.string().email({ message: "Format email tidak valid." }),
age: z.number().min(18, { message: "Anda harus berusia minimal 18 tahun." }),
});
// 2. Secara ajaib, kita mendapatkan tipe TypeScript dari skema!
type User = z.infer<typeof userSchema>;
function prosesRegistrasiDenganZod(data: unknown) { // Terima data sebagai 'unknown' agar lebih aman
// 3. Validasi dengan `safeParse`
const validationResult = userSchema.safeParse(data);
if (!validationResult.success) {
// Jika validasi gagal, tampilkan semua error dengan rapi
console.error("Error Validasi:", validationResult.error.errors);
return;
}
// Jika sukses, kita tahu `validationResult.data` 100% aman dan sesuai tipe User
const validUser: User = validationResult.data;
console.log("Registrasi berhasil untuk:", validUser.username);
// ...lanjutkan proses ke database
}
// Kasus sukses
prosesRegistrasiDenganZod({ username: 'hadie', email: '[email protected]', age: 30 });
// Kasus gagal
prosesRegistrasiDenganZod({ username: 'al', email: '[email protected]', age: 25 });
Lihat perbedaannya?
Deklaratif & Bersih: Aturan didefinisikan sekali di dalam skema, bukan di dalam logika fungsi.
Type-Safe: Kita mendapatkan tipe
User
gratis, yang bisa kita gunakan di seluruh aplikasi kita.Penanganan Error Terpusat:
safeParse
memberikan objek error yang detail dan mudah diproses.
Step-by-Step Membangun Skema dengan Zod
Langkah 1: Tipe Data Dasar
Zod menyediakan “konstruktor” untuk semua tipe data primitif.
z.string();
z.number();
z.boolean();
z.date();
Langkah 2: Menambahkan Aturan (Chaining Methods)
Inilah kekuatan Zod. Kita bisa “merangkai” aturan-aturan pada tipe data dasar.
// Sebuah string, yang tidak boleh kosong, dan harus format email
z.string().min(1).email();
// Sebuah angka, yang harus integer, dan nilainya lebih besar dari 0
z.number().int().positive();
// Sebuah string yang opsional (boleh `undefined`)
z.string().optional();
Langkah 3: Mendefinisikan Objek (z.object
)
Ini adalah yang paling sering kita gunakan untuk form.
const productSchema = z.object({
id: z.string().uuid(), // Harus format UUID
name: z.string().min(3),
price: z.number().nonnegative(), // Tidak boleh negatif
inStock: z.boolean().default(true), // Punya nilai default
tags: z.array(z.string()).optional(), // Array of string, opsional
});
Langkah 4: Validasi dengan parse
vs. safeParse
(PENTING!)
Zod punya dua cara utama untuk validasi:
schema.parse(data)
:Jika data valid, ia akan mengembalikan data yang sudah bersih.
Jika data tidak valid, ia akan melemparkan error (throw an error). Ini akan menghentikan eksekusi kodemu jika tidak ditangani dengan
try...catch
.Kapan digunakan? Di tempat di mana kamu sangat yakin datanya seharusnya valid (misal, data antar-server internal).
schema.safeParse(data)
:Ini tidak pernah melemparkan error.
Ia selalu mengembalikan sebuah objek dengan format:
{ success: boolean, data?: T, error?: ZodError }
Kapan digunakan? Hampir selalu saat menangani input dari luar, seperti input form pengguna atau respon API eksternal, di mana kegagalan validasi adalah hal yang wajar. Inilah yang kita gunakan dengan React Hook Form.
Langkah 5: Mengakses Pesan Error
Saat menggunakan safeParse
, jika success
adalah false
, kita bisa mengakses result.error
untuk mendapatkan detailnya.
const result = userSchema.safeParse({ username: "a" });
if (!result.success) {
// result.error.errors adalah sebuah array
// [{ "code": "too_small", "path": ["username"], "message": "..." }]
console.log(result.error.errors[0].message);
// Output: "Username minimal 3 karakter."
}
Kesimpulan: Kenapa Zod adalah Pilihan Tepat
Dengan mengintegrasikan Zod ke dalam alur kerjamu, kamu mendapatkan:
Keandalan: Kamu bisa percaya pada bentuk datamu.
Kejelasan: Aturan data terpusat dan mudah dibaca.
Efisiensi: Tipe TypeScript dibuatkan untukmu, menghemat waktu dan mencegah bug.
Zod bukan hanya library validasi; ia adalah alat untuk menulis kode yang lebih robust, aman, dan menyenangkan. Ketika dipasangkan dengan React Hook Form, Zod mendefinisikan “apa” (aturannya), sementara React Hook Form mengurus “bagaimana” (menampilkan dan mengelolanya di UI). Mereka adalah tim impian yang sesungguhnya.