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:
// 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
// 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:
// 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:
// 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 bentrokPola 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).
// 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...// 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.
// SALAH: tanpa titik di akhir
Route::name('admin')->group(function () {
Route::get('/dashboard', ...)->name('dashboard');
// nama jadinya: admindashboard (menempel! susah dibaca, rawan typo)
});// 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.