Di samping path, method, dan body, setiap request HTTP membawa header — daftar metadata berupa pasangan nama dan nilai yang menjelaskan isi kiriman. Header Content-Type memberi tahu format body, header Accept menyatakan format response apa yang bisa diterima klien, dan header Authorization lazim dipakai untuk mengirim token akses. Object Request membaca semuanya lewat method header(), hasHeader(), dan bearerToken(), plus sekelompok method negosiasi format seperti accepts() dan expectsJson(). Chapter ini membedah semuanya dengan nilai yang kita uji langsung di sandbox.
Membaca dan Memeriksa Header #
Method header('Nama-Header') mengembalikan nilai header sebagai string — atau null jika header tidak dikirim. Method hasHeader() memeriksa keberadaannya tanpa membaca nilainya. Route berikut merangkum pembacaan header standar, header kustom X-Kota, dan token bearer sekaligus:
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::get('/info-header', function (Request $request) {
return [
'accept' => $request->header('Accept'),
'punya_accept' => $request->hasHeader('Accept'),
'kota' => $request->header('X-Kota'),
'punya_kota' => $request->hasHeader('X-Kota'),
'token_bearer' => $request->bearerToken(),
'menerima_json' => $request->accepts('application/json'),
'ingin_json' => $request->wantsJson(),
'mengharapkan_json' => $request->expectsJson(),
];
});Di runner, header request kita set lewat parameter $server pada Request::create() — setiap header ditulis sebagai kunci HTTP_ diikuti nama header dalam huruf besar:
<?php
// uji-header.php — jalankan dari root proyek Laravel
use Illuminate\Contracts\Http\Kernel;
use Illuminate\Http\Request;
require __DIR__.'/vendor/autoload.php';
$app = require __DIR__.'/bootstrap/app.php';
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
$kernel = $app->make(Kernel::class);
$kasus = [
'tanpa header tambahan' => [],
'Accept: text/html + X-Kota: Bandung' => [
'HTTP_ACCEPT' => 'text/html',
'HTTP_X_KOTA' => 'Bandung',
],
'Authorization: Bearer + Accept: application/json' => [
'HTTP_ACCEPT' => 'application/json',
'HTTP_AUTHORIZATION' => 'Bearer 7|CONTOH_TOKEN_SANCTUM',
],
];
foreach ($kasus as $label => $server) {
$response = $kernel->handle(
Request::create('http://localhost:8000/info-header', 'GET', [], [], [], $server)
);
echo $label.PHP_EOL.'→ '.$response->getContent().PHP_EOL.PHP_EOL;
}Output yang Dihasilkan:
tanpa header tambahan
→ {"accept":"text\/html,application\/xhtml+xml,application\/xml;q=0.9,*\/*;q=0.8","punya_accept":true,"kota":null,"punya_kota":false,"token_bearer":null,"menerima_json":true,"ingin_json":false,"mengharapkan_json":false}
Accept: text/html + X-Kota: Bandung
→ {"accept":"text\/html","punya_accept":true,"kota":"Bandung","punya_kota":true,"token_bearer":null,"menerima_json":false,"ingin_json":false,"mengharapkan_json":false}
Authorization: Bearer + Accept: application/json
→ {"accept":"application\/json","punya_accept":true,"kota":null,"punya_kota":false,"token_bearer":"7|CONTOH_TOKEN_SANCTUM","menerima_json":true,"ingin_json":true,"mengharapkan_json":true}Baris pertama memperlihatkan perilaku request tanpa header eksplisit: Laravel memberi nilai Accept bawaan berupa daftar format HTML dan XML, ditutup wildcard */* — itulah sebabnya kota dan token_bearer bernilai null di sana. Header kustom X-Kota terbaca utuh di skenario kedua, dan nama header bersifat case-insensitive: $request->header('X-Kota') maupun x-kota mengembalikan nilai yang sama.
Bearer Token dari Header Authorization #
Skenario ketiga mengirim header Authorization: Bearer 7|CONTOH_TOKEN_SANCTUM — format standar pengiriman token API. Method bearerToken() mengurai header tersebut dan mengembalikan bagian setelah kata Bearer :
"token_bearer": "7|CONTOH_TOKEN_SANCTUM"Pola inilah yang dipakai Laravel Sanctum saat client API mengakses route yang dilindungi middleware auth:sanctum. Ketika header Authorization tidak ada atau tidak diawali Bearer , method ini mengembalikan null — seperti pada dua skenario pertama.
Negosiasi Format: accepts(), wantsJson(), expectsJson() #
Tiga method terakhir pada route kita adalah alat negosiasi format response, dan hasil uji di atas memperlihatkan perbedaannya:
| Method | Pertanyaan yang dijawab | Nilai saat Accept bawaan | Nilai saat Accept: application/json |
|---|---|---|---|
accepts('application/json') | Apakah klien bersedia menerima tipe konten ini? | true | true |
wantsJson() | Apakah format JSON adalah pilihan utama klien? | false | true |
expectsJson() | Seperti wantsJson(), ditambah kasus AJAX tanpa preferensi | false | true |
Nilai menerima_json yang tetap true pada skenario pertama bisa mengejutkan: daftar Accept bawaan memuat wildcard */*, sehingga klien dianggap menerima format apa pun. Bandingkan dengan ingin_json yang false — wantsJson() hanya melihat tipe pertama dalam daftar prioritas, dan tipe pertama pada Accept bawaan adalah text/html, bukan JSON. Method expectsJson() mengembalikan true ketika wantsJson() benar, atau ketika request datang sebagai AJAX tanpa preferensi konten spesifik. Dalam praktik, expectsJson() dipakai untuk memutuskan: tampilkan halaman error HTML, atau kirim JSON berisi pesan error.
Mengatur Header pada Feature Test #
Untuk menguji handler yang bergantung pada header, feature test menyediakan withHeaders() dan postJson(). Route kecil berikut memeriksa format body:
Route::post('/periksa-json', function (Request $request) {
return [
'konten_tipe' => $request->header('Content-Type'),
'adalah_json' => $request->isJson(),
];
});Kedua cara pengujian tersebut menghasilkan:
public function test_header_kustom_dan_json(): void
{
$response = $this->withHeaders([
'Accept' => 'application/json',
'X-Kota' => 'Surabaya',
])->get('/info-header');
dump($response->json());
$response = $this->postJson('/periksa-json', ['nama' => 'Budi']);
dump($response->json());
$this->assertSame(200, $response->status());
}Output yang Dihasilkan:
array:8 [
"accept" => "application/json"
"punya_accept" => true
"kota" => "Surabaya"
"punya_kota" => true
"token_bearer" => null
"menerima_json" => true
"ingin_json" => true
"mengharapkan_json" => true
]
array:2 [
"konten_tipe" => "application/json"
"adalah_json" => true
]Method withHeaders() menimpa header permintaan sehingga skenario Accept: application/json dan X-Kota: Surabaya terbaca utuh di handler, sementara postJson() otomatis melengkapi body JSON dengan Content-Type: application/json yang membuat isJson() bernilai true. Beragam method pembacaan request lainnya masih tersedia di dokumentasi requests
.
Kini kita bisa membaca hampir semua aspek request: parameter, query string, body, header, sampai pengguna yang login. Satu pertanyaan praktis masih tersisa: ketika ada puluhan route terdaftar, bagaimana kita memastikan route yang kita tulis benar-benar terdaftar dengan method, middleware, dan nama yang kita maksudkan? Chapter penutup section ini membahas php artisan route:list sebagai alat utamanya.