Validasi memeriksa data kiriman sebelum dipakai: field wajib ada, tipenya benar, nilainya masuk akal. Di Laravel, kamu cukup menulis aturannya di $request->validate([...]), dan Laravel yang mengecek, menolak, dan menyusun pesan error-nya. Bayangin petugas pendaftaran buku baru di perpustakaan yang memegang daftar syarat: judul wajib ada, stok harus angka. Formulir yang gak lengkap dikembalikan dengan catatan di sebelah tiap kolom yang salah, dan bukunya gak pernah masuk rak. Kenapa server wajib memeriksa dan apa arti status 422 sudah dibahas di pelajaran Validasi Input. Di sini kita lihat cara Laravel melakukannya.
🧪 Tebakan cepat: klien mengirim
{"title": "Ronggeng Dukuh Paruk", "author": "Ahmad Tohari", "stock": 1, "is_admin": true}. Aturannya cuma untuktitle,author,stock, danisbn. Apakahis_adminikut ada di$validated? Tebak dulu, jawabannya ada di bagian "Kalau lolos: $validated".
Aturan untuk buku baru
App Perpustakaan menerima buku baru lewat API. Ini route-nya di routes/api.php (file ini dibuat dengan php artisan install:api, dan alamatnya otomatis diawali /api):
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::post('/books', function (Request $request) {
$validated = $request->validate([
'title' => 'required|string|max:255',
'author' => 'required|string|max:255',
'stock' => 'required|integer|min:0',
'isbn' => 'nullable|string',
]);
return response()->json($validated, 201);
});
$request->validate([...])menerima daftar field dan aturannya. Aturan untuk satu field dipisah tanda pipa|. Bentuk array juga boleh:['required', 'string', 'max:255'].required: wajib ada dan gak kosong. Field yang gak dikirim,null,"", atau cuma spasi semuanya gagal.string: harus teks.integer: harus bilangan bulat (2dan"2"lolos,2.5dan"abc"gagal).max:255danmin:0membandingkan ukuran: untuk field yang punyaintegerataunumeric, ukurannya nilai angkanya; untuk teks, jumlah karakternya.nullable: bolehnull. Kalau nilainyanull, aturan lain di field itu gak dicek.- Kalau semua lolos, kode di bawah
validate()jalan dan$validatedberisi datanya.
Aturan lain yang sering dipakai:
| Aturan | Artinya |
|---|---|
numeric |
angka, boleh desimal |
email |
format alamat email |
in:novel,nonfiksi |
harus salah satu dari daftar |
unique:books,isbn |
belum ada di kolom isbn tabel books |
Kalau gagal: 422 dengan message dan errors
Kirim body kosong {} dengan header Accept: application/json, dan Laravel menjawab:
HTTP/1.1 422 Unprocessable Content
Content-Type: application/json
{
"message": "The title field is required. (and 2 more errors)",
"errors": {
"title": ["The title field is required."],
"author": ["The author field is required."],
"stock": ["The stock field is required."]
}
}
| Body yang dikirim | Status | Isi errors |
|---|---|---|
{} |
422 | title, author, stock: The ... field is required. |
{"title": "Ronggeng Dukuh Paruk", "author": "Ahmad Tohari", "stock": -1} |
422 | stock: The stock field must be at least 0. |
{"title": "Ronggeng Dukuh Paruk", "author": "Ahmad Tohari", "stock": -1.5} |
422 | stock: The stock field must be an integer. The stock field must be at least 0. |
{"title": "Ronggeng Dukuh Paruk", "author": "Ahmad Tohari", "stock": 1} |
201 | (gak ada) |
- Begitu ada aturan yang gagal,
validate()melemparValidationException. Kode di bawahnya gak jalan sama sekali, dan Laravel menjawab 422 sendiri. errorsberisi daftar pesan per field. Satu field bisa punya beberapa pesan, seperti-1.5di atas: bukan bilangan bulat, dan kurang dari 0.requiredyang gagal menghentikan aturan lain di field itu, jadi body kosong cuma dapat satu pesan per field.messageadalah pesan pertama, ditambah(and 1 more error)atau(and 2 more errors)kalau ada lebih dari satu.- Pesan-pesan itu bawaan Laravel 13 dalam bahasa Inggris, dari file bahasa yang bisa kamu terjemahkan.
Kalau lolos: $validated
validate() mengembalikan cuma field yang punya aturan. Body {"title": "Ronggeng Dukuh Paruk", "author": "Ahmad Tohari", "stock": 1, "is_admin": true} dijawab 201 dengan {"title":"Ronggeng Dukuh Paruk","author":"Ahmad Tohari","stock":1}. is_admin dibuang. Itu jawaban tebakannya. Makanya $validated aman diteruskan ke Book::create($validated), sedangkan $request->all() membawa semua field kiriman.
Sebelum dicek, semua teks lewat dua middleware bawaan: spasi di ujung dibuang (TrimStrings), lalu teks kosong jadi null (ConvertEmptyStringsToNull). Jadi "title": " " gagal di required, dan "isbn": "" lolos sebagai null karena nullable.
Header Accept: 422 atau redirect
Laravel memilih bentuk jawabannya dari header Accept:
| Request | Jawaban kalau gagal |
|---|---|
dengan Accept: application/json |
422 dengan JSON message dan errors |
| tanpa header itu (form dari browser) | 302 redirect balik ke halaman sebelumnya, error-nya disimpan di session |
Untuk form HTML, redirect itu yang kamu mau: halaman form-nya terbuka lagi, dan Blade menampilkan pesannya lewat @error('title') {{ $message }} @enderror. Untuk klien API (aplikasi mobile, fetch), kirim selalu Accept: application/json, kalau gak mereka cuma melihat redirect ke http://localhost.
Form Request: aturan di class sendiri
Kalau aturannya panjang atau dipakai di beberapa tempat, pindahkan ke Form Request:
php artisan make:request StoreBookRequest
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreBookRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
'title' => 'required|string|max:255',
'author' => 'required|string|max:255',
'stock' => 'required|integer|min:0',
'isbn' => 'nullable|string',
];
}
}
Route::post('/books', function (StoreBookRequest $request) {
return response()->json($request->validated(), 201);
});
- Cukup tulis
StoreBookRequestsebagai tipe parameternya. Laravel memvalidasi sebelum function-nya jalan, dengan hasil gagal yang sama: 422 atau redirect. $request->validated()mengembalikan data yang lolos, sama seperti$validatedtadi.authorize()menentukan siapa yang boleh mengirim request ini. File buatanmake:requestberisireturn false;, dan selama begitu, semua request dijawab403dengan pesanThis action is unauthorized.
⚠️ Jebakan yang sering ketemu
- Klien API tanpa
Accept: application/json. Validasi yang gagal jadi redirect 302, bukan 422 JSON. authorize()masihreturn false. Form Request-nya menolak semua request dengan 403, bahkan sebelum aturannya dicek.- Menyimpan
$request->all(). Field yang gak punya aturan ikut terbawa. Simpan$validated. - Lupa
nullabledi field opsional."isbn": ""jadinull, lalu gagal distring:The isbn field must be a string. - Pesannya harus persis pesan Laravel. Latihannya memanggil route-mu dengan body kosong, jadi output-nya
POST /products → 422lalu JSON dengan pesan sepertiThe name field is required.. Yang dinilai:required,max:255, dua baris itu, dan beberapa kiriman lain: harga500, nama 256 huruf, dancategoryberisinull.
TL;DR: $request->validate([...]) memeriksa input dengan aturan yang dipisah |: required (wajib ada, gak kosong), string, integer, max:255 dan min:0 (nilai angka untuk field angka, jumlah karakter untuk teks), dan nullable (boleh null). Kalau ada yang gagal, kode di bawahnya gak jalan dan Laravel menjawab 422 dengan message (pesan pertama plus (and N more errors)) dan errors per field, asalkan request-nya membawa Accept: application/json; tanpa header itu, jawabannya redirect 302. Kalau lolos, $validated cuma berisi field yang punya aturan. Aturan yang panjang dipindah ke Form Request (php artisan make:request StoreBookRequest), yang authorize()-nya harus diubah jadi return true.