Selama section ini kita memvalidasi field yang datar: satu nama field, satu nilai. Aplikasi nyata sering lebih rumit — endpoint API menerima JSON berlapis, satu pesanan berisi daftar menu yang tiap itemnya punya kuantitas, dan form dinamis menambah baris kontak sesuka pengguna. Untuk semua itu, validasi Laravel sanggup menyelam ke kedalaman struktur data dengan notasi titik dan wildcard *. Chapter penutup section ini merangkai teknik validasi data kompleks: aturan array bersarang, pesan per-item, penggabungan default, sampai trik validasi parsial untuk halaman frontend modern.
Memvalidasi Body JSON #
Request yang mengirim Content-Type: application/json ditangani validate() seperti biasa — tidak ada sintaks khusus. Data diakses memakai notasi titik yang sudah akrab dari Arr::get(). Endpoint pemesanan makanan berikut menerima pelanggan dan daftar pesanan:
class StoreOrderRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'pelanggan.nama' => ['required', 'string', 'min:3'],
'pelanggan.email' => ['required', 'email'],
'pesanan' => ['required', 'array', 'min:1'],
'pesanan.*.menu' => ['required', 'string'],
'pesanan.*.qty' => ['required', 'integer', 'min:1', 'max:10'],
'pesanan.*.catatan' => ['nullable', 'string'],
];
}
public function messages(): array
{
return [
'pesanan.*.qty.min' => 'Jumlah pesanan :position minimal :min.',
'pesanan.*.qty.max' => 'Jumlah pesanan :position maksimal :max.',
];
}
}Aturan 'pelanggan.nama' menjangkau {"pelanggan": {"nama": ...}} pada body JSON. Wildcard 'pesanan.*.menu' memeriksa menu pada setiap elemen array pesanan. Pesan kustom pada messages() memakai pola asterisk yang sama — dan perhatikan placeholder :position yang terisi nomor urut item, satu-satunya cara memberi tahu pengguna item keberapa yang bermasalah.
Controller-nya tetap ramping, dengan tambahan penggabungan nilai default:
public function store(StoreOrderRequest $request)
{
$validated = $request->validated();
$validated['status'] = 'baru'; // default yang digabung manual
return response()->json($validated, 201);
}Request Valid: 201 dengan Data Bersih #
POST berisi dua item pesanan yang sah menghasilkan:
Output yang Dihasilkan:
status: 201
{"pelanggan":{"nama":"Budi Santoso","email":"[email protected]"},"pesanan":[{"menu":"Nasi Goreng","qty":2,"catatan":"pedas"},{"menu":"Es Teh","qty":1,"catatan":null}],"status":"baru"}Struktur bersarang kembali utuh dari validated() — hanya field yang dideklarasikan rules-nya yang lolos — dan status ikut tergabung. Pola merge default seperti ini berguna untuk kolom yang tidak seharusnya diisi klien (status, created_by, dsb.).
Bentuk Error 422 untuk Field Bersarang #
Kekuatan sesungguhnya terlihat saat data bermasalah di berbagai kedalaman sekaligus. Request berikut: nama pelanggan terlalu pendek, email salah format, menu kedua kosong, kuantitas pertama nol, dan kuantitas kedua 15:
Output yang Dihasilkan:
status: 422
{"message":"The pelanggan.nama field must be at least 3 characters. (and 4 more errors)","errors":{"pelanggan.nama":["The pelanggan.nama field must be at least 3 characters."],"pelanggan.email":["The pelanggan.email field must be a valid email address."],"pesanan.1.menu":["The pesanan.1.menu field is required."],"pesanan.0.qty":["Jumlah pesanan 1 minimal 1."],"pesanan.1.qty":["Jumlah pesanan 2 maksimal 10."]}}Bentuk errors adalah object dengan key berupa path field lengkap — pelanggan.nama, pesanan.1.menu, pesanan.0.qty — dan nilai berupa array pesan. Frontend cukup memetakan key tersebut ke elemen form yang sesuai. Pesan kustom kita juga bekerja: Jumlah pesanan 1 minimal 1. menunjukkan :position terisi 1 untuk item pertama (indeks 0) dan 2 untuk item kedua (indeks 1) — posisi dihitung dari satu agar manusiawi dibaca.
Validasi Parsial untuk Frontend Modern #
Halaman SPA sering ingin memvalidasi satu field begitu pengguna selesai mengisinya, tanpa menunggu submit. Di Laravel versi sebelumnya pola ini dikerjakan lewat method validateOnly() di sisi klien; pada Laravel 13 mekanismenya digantikan Precognition — sistem validasi prediktif yang memakai header HTTP. Route diberi middleware precognitive:
Route::post('/api/orders', [OrderController::class, 'store'])
->name('api.orders.store')
->middleware('precognitive');Klien mengirim header Precognition: true plus Precognition-Validate-Only: pelanggan.email untuk meminta validasi field tersebut saja. FormRequest otomatis menyaring rules-nya sesuai header:
Output yang Dihasilkan:
status: 422
{"message":"The pelanggan.email field must be a valid email address.","errors":{"pelanggan.email":["The pelanggan.email field must be a valid email address."]}}
email valid:
status: 204
header Precognition-Success: trueMeski body request juga berisi nama yang terlalu pendek, hanya error pelanggan.email yang dikembalikan — rules lain tidak dijalankan. Saat email valid, response 204 (tanpa konten) dengan header Precognition-Success: true menjadi sinyal “aman, lanjut”. Perlu dicatat bahwa validasi parsial ini hanya bekerja lewat FormRequest; controller tidak pernah tereksekusi pada request precognitive. Paket frontend Laravel (Inertia dengan Vue/React) memakai mekanisme inilah di balik helper useForm miliknya.
Menyiapkan Input dengan prepareForValidation() #
Data dinamis dari klien sering tidak lengkap. Chapter FormRequest telah memperkenalkan prepareForValidation(); untuk array bersarang, method ini juga tempat mengisi default per-item:
protected function prepareForValidation(): void
{
$this->merge([
'pelanggan' => array_merge(
['nama' => '', 'email' => ''],
$this->input('pelanggan', []),
),
]);
}Merge di atas menjamin key pelanggan.nama dan pelanggan.email selalu ada sebelum rules dievaluasi, sehingga error-nya konsisten meski klien lupa mengirim objek pelanggan sama sekali.
Dari field datar di chapter pertama sampai array bersarang, JSON API, dan validasi parsial — perangkat validasi Laravel telah kita jelajahi tuntas. Penguji terakhir bagi sistem validasi adalah bagaimana Laravel sendiri mengujinya: feature test assertValid, assertInvalid, dan assertSessionHasErrors yang menyertai kita sepanjang section ini akan dibedah lebih formal di section Testing. Titik awal yang tepat adalah dokumentasi Validation
dan dokumentasi HTTP Tests
.