Server Action
Fungsi yang berjalan di server tetapi dipanggil dari komponen seperti fungsi biasa, tanpa membuat endpoint sendiri.
Membaca sekitar 2 menit
Fungsi yang berjalan di server tetapi dipanggil dari komponen seperti fungsi biasa, tanpa membuat endpoint sendiri.
Semua perubahan data (tambah, ubah, hapus) lewat action dengan urutan tetap: cek izin, validasi dengan Zod, panggil service, catat audit, lalu revalidate.
Action terlihat seperti fungsi lokal, padahal pintunya terbuka untuk siapa saja. Karena itu izin dicek di dalamnya.
Masalahnya dulu
Di User Role Management, setiap tombol Tambah, Ubah, dan Hapus pada manajemen user, role, feature, matriks izin, maupun data item harus berujung pada perubahan data di server. Cara lama: membuat endpoint API satu per satu, memanggilnya dengan fetch, lalu mengurus status loading dan error sendiri. Untuk puluhan operasi, pola itu berulang dan rawan terlupa mengecek izin.
Apa yang dilakukan server action
Server action adalah fungsi async yang diberi penanda "use server". Kita memanggilnya dari komponen seperti fungsi biasa, sementara Next.js yang mengurus pengiriman datanya lewat HTTP POST. Tidak ada alamat endpoint yang perlu ditulis manual, dan tipe argumen serta hasilnya ikut terbawa ke komponen.
Terlihat seperti fungsi lokal di dalam kode, padahal ia adalah pintu HTTP yang terbuka untuk siapa saja.
Urutan yang selalu sama di ngodingan ini
Setiap action mengikuti langkah yang seragam di dalam pembungkus handleAction, sehingga mudah dibaca dan mudah diaudit keamanannya:
export async function deleteItemAction(id: string) {
return handleAction(async () => {
await requirePermission("item", "delete"); // 1. cek sesi, izin RBAC, & rate limit
const uuid = parseInput(uuidSchema, id); // 2. validasi input dengan Zod
await deleteItem(uuid); // 3. panggil service database
revalidatePath("/dashboard/items"); // 4. segarkan cache halaman
}, "Data Item berhasil dihapus");
}Izin dicek paling awal melalui requirePermission, sebelum validasi Zod dijalankan, supaya pengguna tanpa hak akses tidak bisa memancing pesan validasi atau membebani parser di server.
Jebakan yang saya temui
- Mengira action sudah aman karena tombolnya disembunyikan di tampilan. Siapa pun bisa menembak request POST langsung ke action, jadi izin wajib dicek ulang di baris pertama.
- Melempar error mentah ke komponen. Di mode produksi Next.js menyamarkan pesan error demi keamanan, sehingga handleAction membungkus hasil menjadi objek terstruktur { ok, message, fieldErrors }.
- Lupa me-revalidate layout atau halaman yang ikut terdampak, misalnya saat izin role diubah maka tampilan sidebar pengguna juga harus ikut disegarkan.
Ringkasnya
Server action memangkas kode penghubung antara form dan database, tetapi sama sekali tidak mengurangi tanggung jawab keamanan. Perlakukan setiap server action selayaknya endpoint publik yang kebetulan nyaman dipanggil.