Validasi — Laravel

Laravel memiliki sistem validasi yang sangat powerful. Validasi di controller: public function store(Request $request) { $validated = $request->validate([…

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 untuk title, author, stock, dan isbn. Apakah is_admin ikut 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);
});

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)

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);
});

⚠️ Jebakan yang sering ketemu

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.

Yang akan kamu pelajari