Middleware — Laravel

Middleware adalah filter yang dijalankan sebelum/setelah request mencapai controller. Membuat middleware: php artisan make:middleware EnsureAdmin class…

Middleware adalah kode yang berdiri di antara request dan controller. Tiap request lewat middleware dulu: middleware boleh memeriksanya, menolaknya, atau meneruskannya ke dalam, lalu memegang response-nya lagi saat keluar. Bayangin masuk gedung kantor. Satpam di gerbang memeriksa semua tamu, resepsionis lantai admin cuma memeriksa tamu lantai itu, dan kunci kartu cuma ada di pintu satu ruangan. Kalau satu pos menolak, kamu gak pernah sampai ke ruangan. Pulangnya kamu melewati pos yang sama dengan urutan terbalik.

🧪 Tebakan cepat: route /admin/dashboard dipasangi dua middleware, LogRequest lalu EnsureApiKey. Masing-masing punya kode sebelum $next($request) dan kode sesudahnya. Dengan controller di tengah, kelima bagian itu jalan dengan urutan apa? Tebak dulu, jawabannya ada di bagian "Sebelum dan sesudah $next".

Bentuk sebuah middleware

Di app Perpustakaan, halaman /admin/dashboard cuma boleh dibuka aplikasi petugas yang membawa header X-Api-Key: secret123. Buat middleware-nya dengan Artisan:

php artisan make:middleware EnsureApiKey
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class EnsureApiKey
{
    public function handle(Request $request, Closure $next): Response
    {
        if ($request->header('X-Api-Key') !== 'secret123') {
            return response()->json(['error' => 'Forbidden'], 403);
        }

        return $next($request);
    }
}

Sebelum dan sesudah $next

Kode di atas $next($request) jalan waktu request masuk. Kode di bawahnya jalan waktu response keluar. Contohnya LogRequest, yang mengukur lama sebuah request:

class LogRequest
{
    public function handle(Request $request, Closure $next): Response
    {
        $start = microtime(true);                 // sebelum: request masuk

        $response = $next($request);              // lapisan di dalam bekerja

        $ms = round((microtime(true) - $start) * 1000);
        $response->headers->set('X-Took', $ms.'ms'); // sesudah: response keluar

        return $response;
    }
}

Ini perjalanan GET /admin/dashboard dengan kunci yang benar:

Langkah Lapisan Yang jalan
1 LogRequest sebelum $next: catat waktu mulai
2 EnsureApiKey sebelum $next: kuncinya cocok, panggil $next
3 Controller menjawab 200 dengan {"message":"Welcome, admin!"}
4 EnsureApiKey sesudah $next: gak ada kode, response diteruskan keluar
5 LogRequest sesudah $next: pasang header X-Took: 18ms

Masuk dari lapisan terluar ke dalam, keluar dari dalam ke luar, seperti bawang yang dikupas lalu ditutup lagi. Itu jawaban tebakannya.

Kalau kuncinya salah, langkah 3 dan 4 gak terjadi: EnsureApiKey mengembalikan 403 tanpa memanggil $next. Langkah 5 tetap jalan, karena 403 itu juga response yang lewat keluar, jadi LogRequest tetap mencatatnya.

Memasang middleware: route, group, atau global

Middleware baru gak jalan sebelum dipasang. Di Laravel 13, pengaturan middleware ada di bootstrap/app.php:

// bootstrap/app.php
->withMiddleware(function (Middleware $middleware): void {
    $middleware->append(LogRequest::class);   // global: semua request
    $middleware->alias([
        'api.key' => EnsureApiKey::class,     // nama pendek untuk dipakai di route
    ]);
})
// routes/web.php
Route::middleware('api.key')->prefix('admin')->group(function () {
    Route::get('/dashboard', [DashboardController::class, 'index']);
    Route::get('/loans', [LoanController::class, 'index']);
});
Dipasang di Caranya Kena ke
Route ->middleware('api.key') di belakang Route::get(...) route itu saja
Group Route::middleware('api.key')->group(...) semua route di dalam group: /admin/dashboard dan /admin/loans
Global $middleware->append(EnsureApiKey::class) semua request, termasuk katalog /books yang dibuka pengunjung

Urutannya: global dulu, lalu group, lalu route, dan di dalam satu daftar dari kiri ke kanan. Laravel juga membawa middleware dengan alias siap pakai, misalnya auth (harus login), throttle:60,1 (paling banyak 60 request per menit), verified (email sudah diverifikasi), dan can:... untuk cek izin (lihat pelajaran Role-based Access Control).

Cara menolak

Ditulis di middleware Yang diterima client
return response()->json(['error' => 'Forbidden'], 403); 403 dengan body {"error":"Forbidden"}
abort(403, 'Kunci API salah.'); 403. Client JSON menerima {"message": "Kunci API salah."}, browser menerima halaman error Forbidden
return redirect('/login'); 302 ke /login. Cocok untuk halaman web, bukan untuk API

Di latihan

Editor latihan cuma punya satu file, jadi class CheckApiKey ditulis di file yang sama dengan route-nya, lalu dipasang dengan ->middleware(CheckApiKey::class). Saat dijalankan, route-nya dipanggil seperti request sungguhan, lewat middleware-mu: tanpa header yang benar, output-nya GET /admin/dashboard → 403 lalu {"error":"Forbidden"}. Middleware selalu berupa class atau alias. Nama function biasa, misalnya ->middleware("checkApiKey"), berakhir dengan error Target class [checkApiKey] does not exist.

⚠️ Jebakan yang sering ketemu

TL;DR: Middleware berdiri di antara request dan controller. Buat dengan php artisan make:middleware EnsureApiKey, isi handle(Request $request, Closure $next): tolak dengan return response()->json(['error' => 'Forbidden'], 403) atau abort(403), teruskan dengan return $next($request). Kode sebelum $next jalan saat request masuk, kode sesudahnya saat response keluar, dan lapisan terluar masuk pertama dan keluar terakhir. Response penolakan tetap lewat keluar melewati middleware di luarnya. Pasang di satu route dengan ->middleware('auth'), di satu area dengan Route::middleware(...)->group(...), atau untuk semua request dengan $middleware->append(...) di bootstrap/app.php, tempat alias juga didaftarkan.

Yang akan kamu pelajari