Di Membuat Router kita menulis router sendiri: daftar definisi rute yang dicocokkan terhadap metode dan URI permintaan, lalu handler yang cocok dipanggil. Routing Laravel dibangun di atas prinsip yang persis sama, tetapi dibekali lapisan fitur produksi — validasi parameter, reverse routing, grup, hingga pembatasan laju permintaan. Pada chapter ini kita akan membedah fitur-fitur tersebut satu per satu mulai dari closure paling sederhana, lalu menutup dengan perbandingan jujur terhadap router buatan sendiri.

Route Dasar dengan Closure #

Route didefinisikan di routes/web.php dengan method yang dinamai sesuai verb HTTP. Bentuk paling sederhana memakai closure sebagai handler, dan nilai yang dikembalikan closure menjadi isi respons.

php
<?php
// routes/web.php
use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return 'Selamat datang di Toko Buku';
});

Route::post('/keranjang', function () {
    return 'Keranjang diperbarui';
});

Route::match(['get', 'post'], '/kontak', function () {
    return 'Hubungi kami';
});

Route::view('/tentang', 'tentang', ['namaToko' => 'Toko Buku Budi']);

Route::redirect('/promo', '/katalog', 301);

Mari kita bedah kelima barisnya:

  1. Route::get('/', ...): hanya permintaan GET ke URI / yang cocok; nilai balik string langsung menjadi respons 200 OK.
  2. Route::post('/keranjang', ...): permintaan GET ke /keranjang tidak akan cocok — Laravel menjawab 405 Method Not Allowed, bukan menjalankan closure.
  3. Route::match([...], ...): mendaftarkan beberapa verb sekaligus untuk satu URI.
  4. Route::view(...): jalan pintas untuk route yang hanya menampilkan template tanpa logika — di sini template resources/views/tentang.blade.php menerima variabel $namaToko.
  5. Route::redirect(...): mengalihkan permanen (301) dari URI lama ke URI baru tanpa controller.

Route Parameter dan Constraint #

Segmen URI yang dinamis ditulis dalam kurung kurawal dan otomatis diteruskan sebagai argumen closure. Kita sudah mengenal teknik ini sebagai placeholder regex di router mini; Laravel menambahkan constraint agar bentuk parameter bisa dipaksa sebelum handler dijalankan.

php
<?php
use Illuminate\Support\Facades\Route;

Route::get('/buku/{slug}', function (string $slug) {
    return "Detail buku: {$slug}";
});

Route::get('/penulis/{id}', function (string $id) {
    return "Profil penulis nomor {$id}";
})->where('id', '[0-9]+');

Route::get('/arsip/{tahun?}', function (?string $tahun = null) {
    return 'Arsip tahun ' . ($tahun ?? 'semua');
});

Tiga bentuk parameter di atas bekerja seperti ini:

  1. {slug}: segmen apa pun setelah /buku/ terikat ke variabel $slug — pencocokan default mengizinkan semua karakter selain /.
  2. ->where('id', '[0-9]+'): URI seperti /penulis/abc tidak cocok dan berujung 404, karena hanya digit yang lolos. Laravel juga menyediakan pintasan ->whereNumber('id'), ->whereAlpha('nama'), dan ->whereUuid('token').
  3. {tahun?} dengan ?string $tahun = null: parameter opsional — URI /arsip dan /arsip/2024 keduanya cocok. Perhatikan penulisan nullable eksplisit ?string $tahun = null, sesuai aturan PHP 8.4 yang kita bahas di Routing Parameters .

Named Route dan Helper route() #

Memberi nama pada route memungkinkan kita membangun URL dari nama, bukan menuliskan path secara manual. Teknik ini dikenal sebagai reverse routing: definisi rute menjadi satu-satunya sumber kebenaran bagi URL.

php
<?php
use App\Http\Controllers\BookController;
use Illuminate\Support\Facades\Route;

Route::get('/buku/{slug}', [BookController::class, 'show'])
    ->name('books.show');

// di controller, view, atau class lain mana pun:
$url = route('books.show', ['slug' => 'belajar-php-dasar']);
// menghasilkan: /buku/belajar-php-dasar

return redirect()->route('books.show', ['slug' => 'belajar-php-dasar']);

Manfaatnya terasa saat path berubah: cukup ubah definisi /buku/{slug} menjadi /produk/{slug}, dan seluruh tautan maupun redirect yang memakai nama books.show ikut berubah tanpa disentuh satu per satu. Bila URL ditulis manual di banyak template, perubahan path menjadi perburuan string yang rawan ada yang terlewat. Router mini kita tidak punya mekanisme ini — di sana setiap tautan ditulis tangan — dan itulah salah satu alasan reverse routing menjadi standar di framework modern.

Mengarahkan Route ke Controller #

Closure nyaman untuk demo dan route kecil, tetapi aplikasi nyata mengarahkan hampir semua route ke controller agar logika bisa diuji dan diorganisir per fitur. Sintaksnya memakai pasangan array [NamaController::class, 'namaMethod'].

php
<?php
use App\Http\Controllers\BookController;
use Illuminate\Support\Facades\Route;

Route::get('/katalog', [BookController::class, 'index']);

Bentuk array ini lebih aman daripada string seperti 'BookController@index' karena BookController::class ikut diperiksa oleh IDE dan static analysis — salah ketik nama class langsung ketahuan saat refactoring. Pembagian tanggung jawabnya sama dengan yang kita rancang di Controller Layer : route hanya memetakan permintaan, controller berisi logika permintaan.

Route Model Binding #

Fitur khas Laravel yang menghemat banyak kode adalah route model binding: parameter route bertipe model Eloquent otomatis diambil dari database. Laravel mencocokkan nama segmen {book} dengan nama argumen $book, lalu menjalankan Book::findOrFail($id) di belakang layar.

php
<?php
use App\Http\Controllers\BookController;
use Illuminate\Support\Facades\Route;

Route::get('/buku/{book}', [BookController::class, 'show']);
php
<?php
// app/Http/Controllers/BookController.php
namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\Book;

class BookController extends Controller
{
    public function show(Book $book)
    {
        // $book sudah berupa instance Book, bukan sekadar id
        return view('books.show', ['book' => $book]);
    }
}

Bila baris tidak ditemukan, Laravel otomatis menjawab 404 — pola “cari atau gagal” yang dulu kita tulis manual dengan findOrFail() di chapter database kini menyatu dengan routing. Kustomisasi juga tersedia, misalnya Route::get('/buku/{book:slug}', ...) agar pencocokan memakai kolom slug, atau binding eksplisit lewat Route::model() untuk kunci non-standar.

Route Group #

Ketika sekumpulan route berbagi awalan URI, middleware, atau prefiks nama, group mencegah kita menulis ulang atribut yang sama berulang kali. Semua route di dalam group() mewarisi atribut dari rantai method sebelumnya.

php
<?php
use App\Http\Controllers\DashboardController;
use App\Http\Controllers\ReportController;
use Illuminate\Support\Facades\Route;

Route::prefix('admin')
    ->middleware(['auth'])
    ->name('admin.')
    ->group(function () {
        Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
        Route::get('/laporan', [ReportController::class, 'index'])->name('reports');
    });

Rantai di atas menghasilkan dua rute sekaligus dengan tiga atribut seragam:

  1. ->prefix('admin'): URI menjadi /admin/dashboard dan /admin/laporan.
  2. ->middleware(['auth']): pengunjung yang belum login dialihkan ke halaman login sebelum controller dijalankan — konsep middleware yang sama dengan Middleware di framework mini.
  3. ->name('admin.'): nama lengkap rute menjadi admin.dashboard dan admin.reports, sehingga pemanggil route('admin.dashboard') tidak bentrok dengan rute dashboard biasa.

Web Routes vs API Routes #

Laravel memisahkan definisi rute ke dalam dua berkas yang mewarisi perilaku berbeda. Pemisahan ini menegaskan kembali pembedaan aplikasi stateful dan stateless dari chapter Stateless vs Stateful .

Aspekroutes/web.phproutes/api.php
Prefiks URItanpa prefiksotomatis diawali /api
Stateberbasis session dan cookiestateless, tanpa session
Middleware bawaansession, verifikasi CSRF, enkripsi cookiepembatas laju throttle:api
Respons tipikalHTML dari BladeJSON
Cocok untukaplikasi web klasik, area adminAPI untuk mobile app dan SPA

Verifikasi CSRF pada web.php hanya berlaku untuk verb yang tidak aman (POST, PUT, PATCH, DELETE) — GET tetap bebas karena dianggap tidak mengubah state. Di api.php tidak ada perlindungan CSRF karena klien tidak memegang cookie session; keamanannya ditangani token yang kita bahas di chapter authentication nanti.

Fallback dan Rate Limiting #

Dua fitur kecil yang sering dilupakan sampai dibutuhkan: halaman penampung untuk URI yang tak cocok, dan pembatasan laju permintaan. Route::fallback() dijalankan ketika tidak ada satu pun rute yang cocok, menggantikan halaman 404 bawaan.

php
<?php
use Illuminate\Support\Facades\Route;

Route::fallback(function () {
    return response('Halaman tidak ditemukan', 404);
});

Rate limiting dibangun dari limiter bernama yang membatasi jumlah permintaan per selang waktu, lalu diterapkan ke route melalui middleware throttle. Definisi limiter dituliskan sekali saat aplikasi di-bootstrap (di Laravel modern melalui bootstrap/app.php atau service provider), dan middleware throttle:nama-limiter tinggal memakainya.

php
<?php
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;

RateLimiter::for('katalog', function (Request $request) {
    return Limit::perMinute(60)->by($request->user()?->id ?: $request->ip());
});
php
<?php
use App\Http\Controllers\CatalogController;
use Illuminate\Support\Facades\Route;

Route::middleware('throttle:katalog')->group(function () {
    Route::get('/katalog', [CatalogController::class, 'index']);
});

Closure limiter di atas mengembalikan batas 60 permintaan per menit yang dihitung per pengguna — atau per alamat IP bila belum login. Ketika batas terlampaui, Laravel otomatis menjawab 429 Too Many Requests tanpa controller pernah dijalankan. Konsep pembatasan laju beserta strategi per-klien ini persis materi Rate Limiting di Section REST API; Laravel menyediakan implementasinya sehingga kita tinggal menetapkan angkanya.

Perbandingan dengan Router Buatan Sendiri #

AspekRouter mini kitaRouting Laravel
Definisi rutearray berisi pola dan handlermethod fluent per verb + berkas terpisah
Pencocokanregex atau pemisahan string manualpencocokan terkompilasi dengan cache rute
Parameterdiekstrak lalu diperiksa manual{param} + where() + binding model otomatis
URL baliktidak ada; tautan ditulis manualnamed route + helper route()
Pengelompokantidak adaprefix/middleware/name berantai
Perlindungantidak adafallback, throttle, CSRF per grup

Tabel ini menegaskan pesan penting section kita: framework bukan sihir, melainkan automasi atas keputusan-keputusan yang pernah kita ambil manual. Membaca kode routing Laravel jadi lebih mudah karena setiap fiturnya punya padanan konseptual di router mini — yang berbeda hanyalah skala dan tingkat kenyamanan.

Ringkasan #

Kini kita menguasai penuh pintu masuk aplikasi Laravel: route closure dan controller, parameter dengan constraint, named route untuk reverse routing, route model binding, grup dengan prefix dan middleware, pemisahan web/API, fallback, hingga rate limiting. Setiap permintaan yang lolos dari gerbang ini akhirnya berujung pada satu kebutuhan: membaca dan menulis data. Kebutuhan itulah yang ditangani Eloquent, ORM resmi Laravel, pada chapter berikutnya.

Referensi #