HTTP Request
Objek Request membungkus semua superglobal PHP jadi satu API yang bisa diuji. Yang penting bukan daftar method-nya, melainkan kebiasaan mengambil input dengan tipe yang benar.
Intisari
$request->input('kunci', $default)membaca query string maupun body, tanpa peduli metodenya.- Pakai method bertipe:
integer(),boolean(),date(),enum()โ bukan cast manual. $request->validated()hanya mengembalikan field yang lolos aturan. Itulah satu-satunya yang aman masuk kecreate().- Berkas unggahan adalah objek
UploadedFile; simpan denganstore(), jangan pernah percaya nama aslinya. - Di balik proxy (ALB, CloudFront), IP dan skema HTTPS hanya benar kalau trusted proxy dikonfigurasi.
Membaca input
public function cari(Request $request)
{
$kata = $request->input('q', ''); // query string atau body
$halaman = $request->integer('page', 1); // sudah int, bukan string
$aktif = $request->boolean('aktif'); // "1", "true", "on", "yes" โ true
$mulai = $request->date('mulai'); // Carbon, atau null
$status = $request->enum('status', StatusPesanan::class);
$semua = $request->all(); // seluruh input โ jangan dipakai untuk mass assignment
$sedikit = $request->only(['q', 'kategori']);
$tanpa = $request->except(['_token']);
if ($request->filled('q')) { /* ada DAN tidak kosong */ }
if ($request->has('q')) { /* ada, meski kosong */ }
if ($request->missing('q')) { /* tidak ada sama sekali */ }
}
Kenapa method bertipe itu penting. Semua input HTTP sampai ke PHP sebagai string.
$request->input('page') menghasilkan "2", bukan 2. Dengan
strict_types aktif, mengoper string itu ke parameter int adalah error; tanpa itu,
ia lolos diam-diam sampai suatu perbandingan berperilaku aneh. $request->integer('page')
menyelesaikan keduanya sekaligus.
Konteks permintaan
$request->user(); // model User, atau null
$request->user()?->id;
$request->path(); // "produk/12"
$request->url(); // tanpa query string
$request->fullUrl(); // dengan query string
$request->method(); // "POST"
$request->isMethod('post');
$request->header('Accept');
$request->bearerToken(); // isi header Authorization: Bearer โฆ
$request->ip();
$request->expectsJson(); // penting untuk error handler
$request->routeIs('admin.*');
Berkas unggahan
if ($request->hasFile('foto') && $request->file('foto')->isValid()) {
// store() membuat nama acak dan aman. JANGAN pakai getClientOriginalName().
$path = $request->file('foto')->store('produk', 's3');
// atau dengan nama yang kamu tentukan sendiri
$path = $request->file('foto')->storeAs('produk', $produk->id.'.jpg', 's3');
}
Tiga hal yang tidak boleh dipercaya dari berkas unggahan: namanya (bisa berisi
../../ atau .php), MIME type yang dikirim klien (dipalsukan dalam satu detik), dan
ukurannya menurut klien. Validasi dengan aturan File::image()->max(2048) yang memeriksa isi
berkasnya, bukan klaimnya โ dan simpan di S3, bukan di dalam public/.
Di balik load balancer
Begitu aplikasimu berjalan di belakang ALB atau CloudFront (Fase 9), $request->ip() akan
mengembalikan IP load balancer, dan $request->isSecure() akan bilang false
meski pengguna memakai HTTPS. Akibatnya: rate limiting per-IP jadi salah sasaran, dan tautan yang dibuat
url() memakai http://.
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
$middleware->trustProxies(
at: '*', // di VPC, hanya ALB yang bisa menjangkau task
headers: Request::HEADER_X_FORWARDED_FOR
| Request::HEADER_X_FORWARDED_HOST
| Request::HEADER_X_FORWARDED_PORT
| Request::HEADER_X_FORWARDED_PROTO,
);
})
at: '*' hanya aman kalau tidak ada yang bisa menghubungi aplikasimu langsung. Kalau
kontainer bisa dicapai dari internet tanpa melewati load balancer, siapa pun bisa memalsukan
X-Forwarded-For dan menembus rate limit. Di Fase 9 hal ini dijamin oleh security group: hanya ALB
yang boleh membuka port aplikasi.
Menguji tanpa browser
$response = $this->postJson('/api/produk', [
'nama' => 'Kopi',
'harga' => 25000,
]);
$response->assertCreated()->assertJsonPath('data.nama', 'Kopi');
Karena Request adalah objek biasa, seluruh siklus HTTP bisa dijalankan di dalam tes tanpa server. Ini yang membuat suite tes Laravel cepat, dan dibahas tuntas di Fase 6.
Latihan: buat rute /echo yang mengembalikan $request->all(),
lalu kirimi ia curl "localhost:8000/echo?page=2&aktif=on". Amati bahwa page berupa
string "2". Ganti responsnya jadi $request->integer('page') dan
$request->boolean('aktif'), lalu bandingkan keluarannya.
Rangkuman ini sengaja dipangkas ke bagian yang dipakai di roadmap. Buka sumber aslinya saat kamu butuh detail lengkap atau referensi parameter.