LaravelRoutingMiddlewarePemula4 mnt baca

Route Group: Prefix dan Middleware Sekaligus

Kelompokkan route admin dengan prefix, middleware, dan penamaan sekaligus.

Analogi: Stempel "Khusus Karyawan" Sekaligus

Bayangkan gedung kantor dengan 20 ruangan khusus karyawan. Tanpa sistem, setiap pintu ditempeli stempel "khusus karyawan" satu per satu, dan kalau aturannya berubah (misalnya tambah sidik jari), kamu harus mengubah 20 pintu.

Route group seperti memberi stempel ke satu lantai sekaligus: "seluruh lantai 3 khusus karyawan". Satu aturan, berlaku untuk semua ruangan di dalamnya. Mau tambah aturan baru? Ubah di satu tempat.

Kenapa Group Ada? Masalah Apa yang Diselesaikan?

Aplikasi nyata punya puluhan route admin yang semuanya butuh tiga hal yang sama: prefix URL /admin, middleware auth (harus login), dan nama route berawalan admin.. Tanpa group, kamu mengulang tiga hal itu di setiap baris:

php
// Tanpa group: pengulangan yang melelahkan dan rawan inkonsistensi
Route::get('/admin/dashboard', [AdminController::class, 'dashboard'])
    ->middleware('auth')->name('admin.dashboard');
Route::get('/admin/users', [AdminController::class, 'users'])
    ->middleware('auth')->name('admin.users');
Route::get('/admin/posts', [AdminController::class, 'posts'])
    ->middleware('auth')->name('admin.posts');
// Lupa ->middleware('auth') di satu baris = halaman admin bisa diakses tanpa login!

Masalahnya bukan cuma capek mengetik. Satu baris yang lupa middleware('auth') adalah lubang keamanan. Group menyelesaikan ini dengan satu sumber kebenaran: aturan ditulis sekali, diterapkan ke semua.

Contoh 1: Group dengan Prefix, Middleware, dan Nama

php
// routes/web.php
use App\Http\Controllers\AdminController;
use Illuminate\Support\Facades\Route;

Route::prefix('admin')           // semua URL diawali /admin
    ->middleware('auth')         // semua butuh login
    ->name('admin.')             // semua nama diawali admin.
    ->group(function () {
        Route::get('/dashboard', [AdminController::class, 'dashboard'])
            ->name('dashboard');   // nama lengkap: admin.dashboard
        Route::get('/users', [AdminController::class, 'users'])
            ->name('users');       // nama lengkap: admin.users
        Route::get('/posts', [AdminController::class, 'posts'])
            ->name('posts');       // nama lengkap: admin.posts
    });

Hasilnya: URL /admin/dashboard, /admin/users, /admin/posts, semua wajib login, dengan nama route admin.dashboard, admin.users, admin.posts. Verifikasi dengan php artisan route:list.

Contoh 2: Group Bersarang dan Group dengan Controller

Untuk area yang lebih kompleks, group bisa bersarang, dan kamu bisa menetapkan controller default:

php
// routes/web.php

// Group bersarang: /admin/laporan/harian
Route::prefix('admin')->middleware('auth')->name('admin.')->group(function () {
    Route::prefix('laporan')->name('laporan.')->group(function () {
        Route::get('/harian', [LaporanController::class, 'harian'])
            ->name('harian'); // nama: admin.laporan.harian, URL: /admin/laporan/harian
    });
});

// Controller group: tidak perlu tulis [XController::class, ...] berulang
Route::controller(ProfilController::class)->group(function () {
    Route::get('/profil', 'show')->name('profil.show');
    Route::get('/profil/edit', 'edit')->name('profil.edit');
    Route::put('/profil', 'update')->name('profil.update');
});

Route::controller() berguna saat satu controller menangani banyak route: nama class ditulis sekali di atas, method-nya disebut sebagai string di tiap route.

Group juga rapi untuk versioning API:

php
// routes/api.php: versi API hidup berdampingan tanpa bentrok
Route::prefix('v1')->group(function () {
    Route::get('/posts', [Api\V1\PostController::class, 'index']);
});

Route::prefix('v2')->group(function () {
    Route::get('/posts', [Api\V2\PostController::class, 'index']);
});
// URL: /api/v1/posts dan /api/v2/posts, controller berbeda, URL tidak bentrok

Pola ini membuat API lama tetap jalan saat kamu merilis versi baru. Klien lama tidak rusak, klien baru dapat fitur baru.

Catatan teknis: name('admin.') dengan titik di akhir adalah konvensi resmi, bukan typo. Titik itu pemisah namespace nama route. Dan ingat: middleware di group berlaku untuk SEMUA route di dalamnya, termasuk route yang kamu tambahkan belakangan. Itu justru tujuannya: tidak ada yang lolos tanpa sadar.

Kesalahan Umum Pemula

Salah: menaruh route publik di dalam group ber-middleware auth (atau sebaliknya).

php
// SALAH: halaman login ikut terkunci oleh auth → redirect loop!
Route::prefix('admin')->middleware('auth')->group(function () {
    Route::get('/login', [AuthController::class, 'login']); // tidak bisa diakses!
    Route::get('/dashboard', [AdminController::class, 'dashboard']);
});
// User belum login → ditendang ke /login → /login butuh login → ditendang lagi...
php
// BENAR: route publik (login) di luar group, yang privat di dalam
Route::get('/admin/login', [AuthController::class, 'login']);
Route::prefix('admin')->middleware('auth')->group(function () {
    Route::get('/dashboard', [AdminController::class, 'dashboard']);
});

Salah: lupa titik di name('admin') sehingga nama route jadi aneh.

php
// SALAH: tanpa titik di akhir
Route::name('admin')->group(function () {
    Route::get('/dashboard', ...)->name('dashboard');
    // nama jadinya: admindashboard (menempel! susah dibaca, rawan typo)
});
php
// BENAR: dengan titik di akhir
Route::name('admin.')->group(function () {
    Route::get('/dashboard', ...)->name('dashboard');
    // nama jadinya: admin.dashboard (rapi, konsisten)
});

Rangkuman

Route group menerapkan prefix, middleware, dan awalan nama ke banyak route sekaligus: satu sumber kebenaran, nol pengulangan, nol route admin yang lupa dikunci. Hati-hati menaruh route publik di dalam group privat. Berikutnya: memberi nama pada route dan mempercepatnya dengan cache.

Tantangan

Area Admin

Buat group dengan prefix admin, middleware auth, dan name prefix admin.. Di dalamnya: GET /dashboard (teks 'Dashboard'), GET /posts (teks 'Kelola Post'). Cek route:list.