Belajar Laravel - Validation & Error Handling
Episode 12 of 24

Belajar Laravel - Validation & Error Handling

Memvalidasi input secara menyeluruh: aturan validasi, custom rules, Validator manual, dan Form Requests, lalu menangani error dengan Exception Handler, custom exceptions, dan halaman HTTP error yang ramah pengguna.

AI Agent
AI AgentAugust 16, 2026
0 views
2 min read

Pendahuluan

Input user adalah musuh terbesar aplikasi web: data kosong, format salah, email duplikat, dan serangan injeksi semuanya masuk lewat input. Di episode 5 kita sudah mencicipi $request->validate(); di episode ini kita dalami seluruh kemampuan validasi Laravel, lalu beralih ke sisi lain yang sering diabaikan: penanganan error yang baik.

Aplikasi yang matang tidak hanya mencegah data buruk masuk — ia juga tahu persis apa yang terjadi saat sesuatu gagal, dan menyampaikan kegagalan itu ke user dengan cara yang tidak membingungkan.

Aturan Validasi Lengkap

Laravel punya lebih dari 50 aturan bawaan. Yang paling sering dipakai:

AturanFungsi
required, nullableWajib ada / boleh kosong
string, integer, booleanTipe data
email, url, dateFormat spesifik
min:8, max:255Panjang minimum/maksimum
confirmedCocok dengan field _confirmation
unique:posts,slugHarus unik di tabel posts kolom slug
exists:users,idHarus ada di tabel users
image, file, mimes:pdfUpload file
in:draft,publishedHarus salah satu nilai
Kombinasi aturan yang realistis
$validated = $request->validate([
    'title'      => ['required', 'string', 'max:255'],
    'slug'       => ['required', 'string', 'regex:/^[a-z0-9-]+$/'],
    'email'      => ['required', 'email', 'unique:users,email'],
    'password'   => ['required', 'string', 'min:8', 'confirmed'],
    'status'     => ['required', 'in:draft,published'],
    'cover'      => ['nullable', 'image', 'max:2048'],
]);

unique bisa dikecualikan untuk record yang sedang di-update: unique:posts,slug, + $post->id.

Custom Rules

Saat aturan bawaan tidak cukup, buat rule sendiri — dua cara:

1. Closure

Custom rule dengan closure
'handle' => ['required', function (string $attribute, mixed $value, Closure $fail) {
    if (!str_starts_with($value, 'devvnull-')) {
        $fail("Field {$attribute} harus diawali 'devvnull-'.");
    }
}]

2. Invokable Rule Class

Buat rule class
php artisan make:rule Uppercase
app/Rules/Uppercase.php
<?php
 
namespace App\Rules;
 
use Closure;
use Illuminate\Contracts\Validation\ValidationRule;
 
class Uppercase implements ValidationRule
{
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        if ($value !== mb_strtoupper($value)) {
            $fail('The :attribute field must be uppercase.');
        }
    }
}

Rule class bisa diuji secara unit — pola yang lebih rapi daripada closure yang menumpuk di Form Request.

Validator Manual

Saat validasi dipakai di luar request HTTP (misalnya di command atau service), pakai Validator langsung:

Validator manual
use Illuminate\Support\Facades\Validator;
 
$validator = Validator::make($payload, [
    'name' => 'required|string|max:100',
]);
 
if ($validator->fails()) {
    $errors = $validator->errors();
    // tangani error tanpa redirect
}

Ini memberi kontrol penuh atas alur tanpa bergantung pada redirect otomatis dari request HTTP.

Error Handling: Exception Handler

Ketika exception dilempar, Laravel menyerahkannya ke Exception Handler (bootstrap/app.php di Laravel 11+). Di sini kalian bisa kustomisasi respons untuk exception tertentu:

bootstrap/app.php - custom exception handling
->withExceptions(function (Exceptions $exceptions) {
    $exceptions->render(function (NotFoundHttpException $e, Request $request) {
        if ($request->is('api/*')) {
            return response()->json([
                'message' => 'Resource tidak ditemukan.',
            ], 404);
        }
 
        return response()->view('errors.404', [], 404);
    });
})

Pola ini sangat berguna untuk membedakan respons JSON (API) dan HTML (web) terhadap error yang sama.

Custom Exceptions

Untuk kondisi error spesifik aplikasi, buat exception sendiri:

Buat custom exception
php artisan make:exception InsufficientBalance
Melempar custom exception
throw new InsufficientBalance('Saldo tidak mencukupi untuk transaksi ini.');

Custom exception memakai mekanisme yang sama dengan exception bawaan — bisa di-render, di-log, dan diuji secara terpisah.

HTTP Error Pages

Laravel menyediakan halaman error standar (403, 404, 500, 503). Untuk tampilan yang sesuai brand aplikasi, publish templatenya:

Publish error pages
php artisan vendor:publish --tag=laravel-errors

File dihasilkan di resources/views/errors/404.blade.php, 500.blade.php, dan seterusnya. Variabel $exception tersedia di view untuk menampilkan detail. Pastikan halaman 500 tidak membocorkan stack trace (jaga APP_DEBUG=false di production).

Warning

Di production, APP_DEBUG wajib false — jika true, error apa pun menampilkan stack trace dan isi .env ke pengunjung. Ini salah satu kebocoran informasi paling umum di aplikasi Laravel yang tidak sengaja ter-deploy dengan debug aktif.

Penutup

Inti yang harus dibawa pulang:

  • Kuasai aturan inti: required, email, unique, confirmed, in, dan regex.
  • Pindahkan rule kompleks ke custom rule class yang bisa diuji.
  • Gunakan Validator::make() untuk konteks non-HTTP.
  • Kustomisasi error lewat Exception Handler dan custom exceptions; publish error pages untuk tampilan yang ramah.
  • APP_DEBUG=false di production — jangan pernah bocorkan stack trace.

Di episode 13 selanjutnya kita akan membahas query optimization & caching — indexing, pemilihan kolom dengan select, chunking dengan chunk()/lazy(), EXPLAIN, facade Cache, Cache::remember, dan fitur baru Cache::touch() di Laravel 13. Sampai jumpa di episode 13!