BAB 5: Routing
Mendefinisikan rute untuk menghubungkan URL dengan logika aplikasi menggunakan sistem routing Laravel.
Di bab sebelumnya kita sudah melihat routing sebagai salah satu fitur unggulan Laravel — dan di sana kita menemukan bahwa empat baris kode sudah cukup untuk mendefinisikan empat endpoint. Sekarang kita buka lapisan itu lebih dalam.
Routing adalah pintu pertama yang diketuk setiap request yang masuk ke aplikasi kamu. Sebelum controller berjalan, sebelum database disentuh, sebelum view dirender — router yang menentukan apakah request itu layak dilanjutkan dan ke mana ia harus pergi.
Anatomi Routing Laravel
Semua rute web didefinisikan di satu file: routes/web.php. File ini diload otomatis oleh Laravel, dan setiap baris di dalamnya adalah deklarasi — “jika ada request ke URL ini dengan method ini, jalankan ini.”
Sintaks dasarnya mengikuti pola yang konsisten:
// routes/web.php
Route::get('/url', function () {
return 'Respons';
});
Route::post('/url', function () {
return 'Respons';
});
Route::put('/url', function () {
return 'Respons';
});
Route::delete('/url', function () {
return 'Respons';
});
Method get, post, put, dan delete masing-masing menangani HTTP method yang sesuai. Ada juga patch untuk pembaruan parsial dan options untuk preflight CORS, tapi keempatnya di atas yang paling sering kamu temui.
Jika kamu ingin satu rute merespons beberapa method sekaligus, gunakan match atau any:
// routes/web.php
// Hanya GET dan POST
Route::match(['get', 'post'], '/catatan/simpan', function () {
return 'Berhasil';
});
// Semua method HTTP
Route::any('/catatan/proses', function () {
return 'Berhasil';
});
Rute ke Controller
Menggunakan closure (fungsi anonim) di dalam routes/web.php cocok untuk prototyping cepat, tapi di aplikasi nyata kamu akan hampir selalu mengarahkan rute ke method di sebuah Controller. Ini menjaga file routes tetap bersih dan logika tetap terorganisir:
// routes/web.php
use App\Http\Controllers\CatatanController;
Route::get('/catatan', [CatatanController::class, 'index']);
Route::get('/catatan/buat', [CatatanController::class, 'create']);
Route::post('/catatan', [CatatanController::class, 'store']);
Route::get('/catatan/{id}', [CatatanController::class, 'show']);
Route::get('/catatan/{id}/edit', [CatatanController::class, 'edit']);
Route::put('/catatan/{id}', [CatatanController::class, 'update']);
Route::delete('/catatan/{id}', [CatatanController::class, 'destroy']);
Format array [ClassName::class, 'methodName'] memberitahu Laravel: arahkan request ini ke method methodName di class ClassName. Controller akan kita pelajari menyeluruh di Bab 7.
Route Resource
Tujuh rute di atas adalah pola CRUD standar yang hampir selalu sama di setiap resource. Laravel mengenali pola ini dan menyediakan jalan pintas:
// routes/web.php
use App\Http\Controllers\CatatanController;
Route::resource('catatan', CatatanController::class);
Satu baris itu menghasilkan ketujuh rute yang sama persis dengan blok kode sebelumnya. Jalankan php artisan route:list untuk memverifikasinya — kamu akan melihat tujuh entri dengan nama rute yang sudah digenerate secara otomatis.
| Method | URI | Action | Route Name |
|---|---|---|---|
| GET | /catatan | index | catatan.index |
| GET | /catatan/create | create | catatan.create |
| POST | /catatan | store | catatan.store |
| GET | /catatan/{catatan} | show | catatan.show |
| GET | /catatan/{catatan}/edit | edit | catatan.edit |
| PUT/PATCH | /catatan/{catatan} | update | catatan.update |
| DELETE | /catatan/{catatan} | destroy | catatan.destroy |
Jika hanya butuh beberapa dari tujuh rute tersebut, gunakan only atau except:
// Hanya buat rute index dan show
Route::resource('catatan', CatatanController::class)->only(['index', 'show']);
// Semua kecuali destroy
Route::resource('catatan', CatatanController::class)->except(['destroy']);
Parameter Rute
URL yang statis tidak cukup untuk aplikasi nyata. Kamu butuh URL yang bisa menerima nilai dinamis — seperti ID pengguna atau slug artikel.
Parameter Wajib
Bungkus nama parameter dengan kurung kurawal:
// routes/web.php
Route::get('/catatan/{id}', function (string $id) {
return 'Catatan dengan ID: ' . $id;
});
Saat request masuk ke /catatan/42, nilai 42 diteruskan ke parameter $id. Nama parameter di URL dan nama variabel di closure harus sama.
Parameter Opsional
Tambahkan tanda tanya untuk membuat parameter opsional, dan berikan nilai default di closure:
// routes/web.php
Route::get('/catatan/{kategori?}', function (?string $kategori = 'umum') {
return 'Kategori: ' . $kategori;
});
Request ke /catatan akan menggunakan nilai default 'umum', sementara /catatan/pekerjaan akan mendapat nilai 'pekerjaan'.
Validasi Format Parameter
Laravel bisa memvalidasi format parameter menggunakan regex atau helper yang lebih ekspresif:
// routes/web.php
// Hanya angka
Route::get('/catatan/{id}', function (string $id) {
return $id;
})->whereNumber('id');
// Hanya huruf
Route::get('/kategori/{nama}', function (string $nama) {
return $nama;
})->whereAlpha('nama');
// Kombinasi huruf dan angka
Route::get('/tag/{slug}', function (string $slug) {
return $slug;
})->whereAlphaNumeric('slug');
Jika request masuk dengan format yang tidak sesuai — misalnya /catatan/abc saat whereNumber dipasang — Laravel otomatis mengembalikan 404.
Named Routes
Nama rute memungkinkan kamu merujuk ke sebuah rute tanpa hardcode URL-nya. Ini penting karena URL bisa berubah, tapi nama rute tidak.
// routes/web.php
Route::get('/catatan', [CatatanController::class, 'index'])->name('catatan.index');
Route::get('/catatan/{id}', [CatatanController::class, 'show'])->name('catatan.show');
Untuk menghasilkan URL dari nama rute, gunakan helper route():
// Di Controller atau View
$url = route('catatan.index'); // '/catatan'
$url = route('catatan.show', ['id' => 5]); // '/catatan/5'
Di Blade template:
<a href="{{ route('catatan.index') }}">Semua Catatan</a>
<a href="{{ route('catatan.show', ['id' => $catatan->id]) }}">Lihat Catatan</a>
Keuntungannya: jika suatu hari kamu mengubah /catatan menjadi /notes, kamu hanya perlu mengubah definisi rute — semua route('catatan.index') di seluruh aplikasi otomatis mengikuti.
Route resource yang dibuat dengan Route::resource() sudah otomatis mendapat nama rute — kamu tidak perlu menamainya secara manual. Jalankan php artisan route:list --names untuk melihat daftar lengkapnya.
Route Groups
Ketika beberapa rute berbagi atribut yang sama — middleware, prefix URL, atau namespace controller — kamu bisa mengelompokkannya dengan Route::group() agar tidak ada pengulangan:
// routes/web.php
// Grup dengan middleware auth
Route::middleware('auth')->group(function () {
Route::get('/catatan', [CatatanController::class, 'index']);
Route::get('/catatan/buat', [CatatanController::class, 'create']);
Route::post('/catatan', [CatatanController::class, 'store']);
});
Semua rute di dalam closure tersebut akan melewati middleware auth sebelum dieksekusi.
Prefix URL juga bisa digrup:
// routes/web.php
Route::prefix('admin')->group(function () {
Route::get('/pengguna', [Admin\PenggunaController::class, 'index']);
Route::get('/catatan', [Admin\CatatanController::class, 'index']);
Route::get('/statistik', [Admin\StatistikController::class, 'index']);
});
Tiga rute di atas menghasilkan /admin/pengguna, /admin/catatan, dan /admin/statistik. Tanpa prefix, kamu harus menulis /admin/ di setiap definisi rute secara manual.
Middleware dan prefix bisa digabung:
// routes/web.php
Route::middleware('auth')
->prefix('admin')
->name('admin.')
->group(function () {
Route::get('/dashboard', [Admin\DashboardController::class, 'index'])->name('dashboard');
Route::resource('pengguna', Admin\PenggunaController::class);
});
Blok di atas menghasilkan rute yang membutuhkan autentikasi, diawali /admin/, dan namanya diawali admin. — misalnya admin.dashboard dan admin.pengguna.index.
Route Model Binding
Ini salah satu fitur routing yang paling menghemat kode. Alih-alih mengambil model dari database secara manual di setiap method controller, Laravel bisa melakukannya secara otomatis.
Tanpa route model binding, kode controller biasanya terlihat seperti ini:
// Cara manual (tanpa route model binding)
Route::get('/catatan/{id}', function (string $id) {
$catatan = Catatan::findOrFail($id);
return view('catatan.show', compact('catatan'));
});
Dengan route model binding implisit, cukup type-hint model di parameter:
// routes/web.php
use App\Models\Catatan;
Route::get('/catatan/{catatan}', function (Catatan $catatan) {
return view('catatan.show', compact('catatan'));
});
Laravel melihat bahwa tipe parameter adalah Catatan dan nama parameter URL adalah {catatan}, lalu secara otomatis mengambil record dari tabel catatan berdasarkan ID. Jika record tidak ditemukan, 404 dikembalikan tanpa kode tambahan.
Secara default binding menggunakan kolom id. Untuk menggunakan kolom lain — misalnya slug — tambahkan nama kolom setelah tanda titik dua:
// routes/web.php
Route::get('/catatan/{catatan:slug}', function (Catatan $catatan) {
return view('catatan.show', compact('catatan'));
});
Request ke /catatan/mencatat-ide-di-pagi-hari akan mengambil record dengan slug = 'mencatat-ide-di-pagi-hari'.
Form Method Spoofing
Browser hanya mendukung method GET dan POST untuk form HTML. Untuk mengirim request PUT, PATCH, atau DELETE dari form, Laravel menggunakan teknik method spoofing dengan directive Blade @method:
{{-- resources/views/catatan/edit.blade.php --}}
<form action="{{ route('catatan.update', $catatan->id) }}" method="POST">
@csrf
@method('PUT')
<input type="text" name="judul" value="{{ $catatan->judul }}">
<textarea name="isi">{{ $catatan->isi }}</textarea>
<button type="submit">Simpan Perubahan</button>
</form>
@csrf menghasilkan token keamanan untuk mencegah serangan CSRF. @method('PUT') menyisipkan field tersembunyi _method=PUT yang dibaca Laravel untuk menentukan method HTTP yang sebenarnya.
Jangan pernah menghilangkan @csrf dari form yang mengirim data ke server. Laravel akan menolak request tersebut dengan error 419 (Page Expired).
Melihat Semua Rute
Saat aplikasi berkembang dan rute bertambah banyak, Artisan menyediakan perintah untuk melihat gambaran keseluruhan:
# Tampilkan semua rute
php artisan route:list
# Tampilkan dengan middleware
php artisan route:list -v
# Filter berdasarkan path
php artisan route:list --path=catatan
# Filter berdasarkan method
php artisan route:list --method=GET
Output route:list menampilkan method, URI, nama rute, dan action yang menanganinya — sangat berguna saat debugging atau memverifikasi bahwa Route::resource() menghasilkan rute yang diharapkan.
Penutup Bab
Routing di Laravel bukan sekadar konfigurasi URL — ini adalah kontrak yang mendefinisikan bagaimana aplikasi kamu berkomunikasi dengan dunia luar. Parameter rute, named routes, route groups, dan route model binding adalah alat yang akan kamu gunakan di hampir setiap proyek.
Yang belum kita sentuh adalah lapisan yang berjalan sebelum request sampai ke controller: middleware. Ini yang menentukan apakah sebuah request layak diteruskan, siapa yang boleh mengaksesnya, dan transformasi apa yang perlu dilakukan sebelum data diolah. Itulah topik bab berikutnya.