โ† Semua pembelajaran / Laravel Nol โ†’ Enterprise
Fase 1 ยท Request, Routing & Blade

Validasi

Validasi bukan soal pesan error yang cantik. Ia adalah batas keamanan: satu-satunya tempat kamu memutuskan bentuk data apa yang boleh masuk ke aplikasimu.

Sumber asli laravel.com Resmi Rangkuman ~8 menit baca

Intisari

  • Form Request memindahkan aturan keluar dari controller dan menyatukannya dengan otorisasi.
  • Gagal validasi otomatis jadi redirect + error di session untuk web, dan JSON 422 untuk permintaan yang mengharap JSON.
  • Pakai $request->validated(), bukan $request->all() โ€” inilah pertahanan terhadap mass assignment.
  • Aturan objek (Password::defaults(), Rule::unique(), File::image()) lebih aman daripada string yang disambung.
  • prepareForValidation() untuk merapikan input sebelum aturan dijalankan.

Form Request: bentuk yang dipakai di proyek nyata

php artisan make:request SimpanProdukRequest
class SimpanProdukRequest extends FormRequest
{
    // Dijalankan LEBIH DULU. false di sini = 403, aturan tidak pernah dievaluasi.
    public function authorize(): bool
    {
        return $this->user()->can('create', Produk::class);
    }

    public function rules(): array
    {
        return [
            'nama'        => ['required', 'string', 'max:120'],
            'slug'        => ['required', 'alpha_dash', Rule::unique('produk')->ignore($this->produk)],
            'harga'       => ['required', 'integer', 'min:0'],
            'kategori_id' => ['required', 'exists:kategori,id'],
            'status'      => ['required', Rule::enum(StatusProduk::class)],
            'tag'         => ['array', 'max:10'],
            'tag.*'       => ['string', 'max:30'],
            'foto'        => ['nullable', File::image()->max(2 * 1024)],
        ];
    }

    // Bersihkan input sebelum aturan berjalan
    protected function prepareForValidation(): void
    {
        $this->merge([
            'slug' => Str::slug($this->input('slug') ?: $this->input('nama')),
        ]);
    }

    public function messages(): array
    {
        return [
            'harga.min' => 'Harga tidak boleh negatif.',
        ];
    }
}
public function store(SimpanProdukRequest $request)
{
    $produk = Produk::create($request->validated());   // โ† hanya field yang lolos aturan

    return redirect()->route('produk.show', $produk);
}

Inilah alasan sebenarnya memakai validated(). Ia mengembalikan hanya field yang punya aturan. Kalau penyerang menambahkan is_admin=1 ke form, field itu tidak muncul di hasilnya, jadi tidak mungkin ikut tersimpan. $request->all() membawa segalanya dan menyerahkan seluruh pertahanan ke properti $fillable di model โ€” satu lapis, bukan dua.

Aturan yang paling sering dipakai

AturanArtinyaCatatan
requiredAda dan tidak kosongBeda dengan present (boleh kosong)
nullableBoleh nullTanpa ini, null gagal di aturan lain
sometimesValidasi hanya kalau field-nya dikirimKunci untuk PATCH
exists:tabel,kolomNilainya ada di databaseSatu query per field
unique:tabel,kolomBelum dipakaiSaat update, wajib ->ignore($model)
confirmedAda field <nama>_confirmation yang samaUntuk password
in:a,b,cSalah satu dari daftarUntuk enum, pakai Rule::enum()
after:tanggal_mulaiPerbandingan antar fieldNama field, bukan nilai

Aturan objek: lebih aman daripada string

'password' => ['required', 'confirmed', Password::defaults()],
'email'    => ['required', 'email', Rule::unique('users')->ignore($this->user)],
'peran'    => ['required', Rule::in(['admin', 'staf'])],
'dokumen'  => ['required', File::types(['pdf'])->max(10 * 1024)],

Keunggulannya bukan estetika: string seperti 'unique:users,email,'.$id gampang salah saat ada koma di data, dan tidak terbaca oleh analisis statis. Bentuk objek diperiksa oleh PHPStan di Fase 6.

Aturan buatan sendiri

// php artisan make:rule KodePosIndonesia
class KodePosIndonesia implements ValidationRule
{
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        if (! preg_match('/^\d{5}$/', (string) $value)) {
            $fail('Kode pos harus lima digit angka.');
        }
    }
}

Bentuk respons kegagalan

Jenis permintaanResponsCara membacanya
Form biasa (web)302 kembali, input lama tersimpan@error('nama') di Blade
Accept: application/json422 berisi objek errorsDitangani frontend
Gagal authorize()403Aturan tidak dievaluasi sama sekali
{
  "message": "The given data was invalid.",
  "errors": {
    "harga": ["Harga tidak boleh negatif."],
    "slug":  ["The slug has already been taken."]
  }
}

Validasi bukan pengganti aturan database. Antara unique diperiksa dan baris disimpan ada jeda; dua permintaan bersamaan bisa lolos keduanya. Validasi menghasilkan pesan yang enak dibaca manusia, unique index di database yang menjamin kebenarannya. Pasang keduanya.

Latihan: buat SimpanProdukRequest lengkap dengan authorize() yang mengembalikan false, lalu kirim permintaan dan pastikan kamu menerima 403, bukan 422 โ€” bukti bahwa otorisasi berjalan lebih dulu. Kembalikan ke true, kirim data tanpa harga, dan bandingkan respons curl biasa dengan curl -H "Accept: application/json".

Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.