Teori lapisan bawang tidak akan lengkap tanpa menulis satu middleware sungguhan. Untungnya Laravel menyediakan generator artisan, jadi kita tidak perlu membuat class dan namespace secara manual. Pada chapter ini kita membangun middleware EnsureTokenIsValid yang memeriksa token sederhana pada query string: request tanpa token valid ditolak lebih awal dengan status 403, sedangkan request yang lolos menerima tambahan header pada response-nya. Lewat satu class kecil ini, kita sekaligus melatih logika before, after, dan cara menguji keduanya.
Membuat Class dengan make:middleware #
Perintah make:middleware membuat file di app/Http/Middleware:
php artisan make:middleware EnsureTokenIsValidOutput yang Dihasilkan:
INFO Middleware [app/Http/Middleware/EnsureTokenIsValid.php] created successfully.Isi file yang dihasilkan artisan terlihat seperti ini:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class EnsureTokenIsValid
{
/**
* Handle an incoming request.
*
* @param Closure(Request): (Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
return $next($request);
}
}Nama class mengikuti konvensi framework: middleware pemeriksa biasanya diawali Ensure atau Verify supaya niatnya terbaca dari nama route. File ini berada di folder app/Http/Middleware dan otomatis mengikuti PSR-4, jadi namespace-nya sudah benar tanpa penyuntingan tambahan. Stub bawaan ini sengaja polos — belum ada aturan apa pun, hanya jalan tolak lurus ke $next($request).
Mari kita bedah anatomi minimum sebuah middleware:
- Method
handle(Request $request, Closure $next)— satu-satunya method wajib; dipanggil framework saat request melewati lapisan ini. - Parameter
$request— objek request yang sedang menembus pipeline, bertipeIlluminate\Http\Request. - Parameter
$next— closure yang meneruskan request ke lapisan berikutnya; memanggil$next($request)berarti mengizinkan request lanjut ke controller. - Return type
Response— middleware wajib mengembalikan response, baik hasil$next($request)maupun response buatan sendiri.
Logika Before: Menolak Lebih Awal #
Sekarang kita isi handle dengan pemeriksaan token. Kode yang berada sebelum pemanggilan $next($request) adalah logika before:
public function handle(Request $request, Closure $next): Response
{
if ($request->query('token') !== 'rahasia-budi') {
return response('Token tidak valid.', 403);
}
$response = $next($request);
// ... logika after di sini
return $response;
}Ketika token tidak cocok, handle langsung mengembalikan response('Token tidak valid.', 403) tanpa memanggil $next($request). Pola ini disebut short-circuit: controller, middleware di dalamnya, hingga query database semuanya tidak pernah dieksekusi. Pengguna menerima jawaban penolakan secepat mungkin, sementara controller tetap bersih dari kode pemeriksaan token.
Logika After: Menyentuh Response Keluar #
Request yang lolos pemeriksaan kita tangkap response-nya ke variabel $response setelah $next($request) kembali. Pada titik ini, response masih berada di tangan kita sebelum berangkat ke pengguna, sehingga bisa dimodifikasi:
$response = $next($request);
$response->headers->set('X-Token-Checked', 'ya');
return $response;Baris tersebut menambahkan header X-Token-Checked sebagai penanda bahwa request memang sudah melewati pemeriksaan token. Pola yang sama bisa dipakai untuk kebutuhan lain: menambah header keamanan, mengganti header Cache-Control, atau mengubah isi response melalui method seperti $response->setContent().
Meregistrasi Per-Route #
Middleware baru belum otomatis aktif — Laravel tidak menebak route mana yang memakainya. Cara paling langsung adalah menempelkannya pada route melalui nama class-nya:
use App\Http\Middleware\EnsureTokenIsValid;
Route::get('/tugas', fn () => 'Daftar tugas')
->middleware(EnsureTokenIsValid::class);Method middleware() menerima nama class lengkap, dan route /tugas kini dibungkus EnsureTokenIsValid di dalamnya. Method yang sama juga menerima array — ->middleware([A::class, B::class]) — dan boleh dipanggil pada Route::group() agar satu tarikan menutup banyak route sekaligus. Penamaan alias yang lebih ringkas dibahas pada chapter tentang registrasi.
Menguji Middleware dengan Feature Test #
Feature test mengirim request sungguhan melewati pipeline, sehingga kita bisa mengamati ketiga skenario: tanpa token, token salah, dan token valid:
public function test_tanpa_token_ditolak(): void
{
$response = $this->get('/tugas');
$response->assertStatus(403);
echo 'tanpa_token: status=', $response->getStatusCode(),
', isi="', $response->getContent(), '"', PHP_EOL;
}
public function test_token_valid_diteruskan_ke_controller(): void
{
$response = $this->get('/tugas?token=rahasia-budi');
$response->assertStatus(200);
echo 'token_valid: status=', $response->getStatusCode(),
', isi="', $response->getContent(), '"',
', header X-Token-Checked="', $response->headers->get('X-Token-Checked'), '"', PHP_EOL;
}Output yang Dihasilkan:
tanpa_token: status=403, isi="Token tidak valid."
token_salah: status=403
token_valid: status=200, isi="Daftar tugas", header X-Token-Checked="ya"Tiga baris output itu membuktikan logika before dan after bekerja: penolakan terjadi sebelum controller (isi tetap pesan middleware), sedangkan request valid diteruskan ke controller dan response-nya membawa jejak header tambahan.
Middleware yang menempel lewat nama class valid, tetapi menulis App\Http\Middleware\EnsureTokenIsValid::class di banyak route cepat menjadi berisik. Chapter berikutnya memindahkan registrasi ke bootstrap/app.php dengan alias, group, dan urutan prioritas yang lebih rapi; seluruh opsi pemasangannya terdokumentasi di dokumentasi middleware
.