Request terkirim bukan akhir cerita — justru di response-lah keputusan diambil. Apakah panggilan berhasil? Data ada di key mana? Berapa sisa kuota di header rate limit? Dan yang paling rawan kesalahan: bagaimana reaksi kita saat status bukan 2xx. Tanpa kebiasaan yang rapi, kode client dipenuhi if ($response->status() === 200) yang rapuh — 201 dan 204 pun sukses. Object Illuminate\Http\Client\Response menyediakan perangkat lengkap untuk membaca dan mengevaluasi response, dan chapter ini mengeksplorasinya satu per satu sampai pola penanganan error yang siap produksi.

Membaca Status dan Header #

Empat method pemeriksaan menutup hampir semua kebutuhan: status() mengembalikan kode HTTP, sementara successful(), failed(), dan ok() mengevaluasi kelompok status:

php
<?php

use Illuminate\Support\Facades\Http;

Http::fake([
    'api.example.com/artikel' => Http::response([
        'data' => [
            ['id' => 1, 'judul' => 'Belajar HTTP Client', 'tag' => ['laravel', 'http']],
            ['id' => 2, 'judul' => 'Belajar Response', 'tag' => ['laravel', 'api']],
        ],
        'meta' => ['total' => 2],
    ], 200, ['X-RateLimit-Remaining' => '57']),
]);

$response = Http::get('https://api.example.com/artikel');

echo 'status: '.$response->status()."\n";
echo 'successful: '.var_export($response->successful(), true)."\n";
echo 'failed: '.var_export($response->failed(), true)."\n";
echo 'ok: '.var_export($response->ok(), true)."\n";
echo 'X-RateLimit-Remaining: '.$response->header('X-RateLimit-Remaining')."\n";

Output yang Dihasilkan:

text
status: 200
successful: true
failed: false
ok: true
X-RateLimit-Remaining: 57

Perbedaannya presisi: successful() benar untuk semua status 2xx, ok() khusus 200, dan failed() menutup rentang 4xx–5xx. Method header($nama) membaca satu header response tanpa pusing soal case-sensitivity.

Membaca Body: json, body, collect, object #

Empat pintu menuju isi response, sesuai selera pengolahan kita. Method json() menerima key path bergaya dot sehingga array bersarang bisa diambil langsung tanpa rantai indeks:

php
<?php

// ... $response dari Http::get('https://api.example.com/artikel') di atas

echo 'data.0.judul: '.$response->json('data.0.judul')."\n";
echo 'meta.total: '.$response->json('meta.total')."\n";
echo 'data.0.tag.1: '.$response->json('data.0.tag.1')."\n";
echo 'tidak-ada (dengan default): '
    .var_export($response->json('meta.habis', 'belum ada'), true)."\n";
echo 'body: '.substr($response->body(), 0, 60)."...\n";

Output yang Dihasilkan:

text
data.0.judul: Belajar HTTP Client
meta.total: 2
data.0.tag.1: http
tidak-ada (dengan default): 'belum ada'
body: {"data":[{"id":1,"judul":"Belajar HTTP Client","tag":["larav...

Key yang tidak ada menghasilkan null — atau nilai default pada parameter kedua, seperti 'belum ada' di atas. Sementara body() mengembalikan string mentah apa adanya untuk response non-JSON.

Dua method sisanya memberi bentuk yang lebih nyaman. collect() mengubah bagian response menjadi Illuminate\Support\Collection, membuka seluruh perangkat collection: pluck, flatten, sum, sampai filter:

php
<?php

$judul = $response->collect('data')->pluck('judul');
echo 'class: '.get_class($judul)."\n";
echo 'judul: '.$judul->implode(', ')."\n";

$tagUnik = $response->collect('data')->pluck('tag')->flatten()->unique()->values();
echo 'tag unik: '.$tagUnik->implode(', ')."\n";

Output yang Dihasilkan:

text
class: Illuminate\Support\Collection
judul: Belajar HTTP Client, Belajar Response
tag unik: laravel, http, api

Terakhir, object() mem-parse JSON menjadi object PHP biasa — nyaman untuk akses property berantai:

php
<?php

$obj = $response->object();
echo 'meta->total: '.$obj->meta->total."\n";
echo 'data[0]->judul: '.$obj->data[0]->judul."\n";

Output yang Dihasilkan:

text
meta->total: 2
data[0]->judul: Belajar HTTP Client

throw dan Keluarganya #

Masalah dengan memeriksa failed() manual adalah kelalaian: satu cabang if yang terlewat, dan response gagal mengalir ke kode seolah sukses. Method throw() membalik pendekatannya — response sukses lewat begitu saja, response gagal melempar RequestException seketika:

php
<?php

use Illuminate\Support\Facades\Http;

Http::fake([
    'api.example.com/artikel' => Http::response(['pesan' => 'kuota habis'], 429),
]);

try {
    Http::get('https://api.example.com/artikel')->throw();
} catch (Illuminate\Http\Client\RequestException $e) {
    echo 'terlempar: '.get_class($e)."\n";
    echo 'pesan exception: '.$e->getMessage()."\n";
    echo 'status via exception: '.$e->response->status()."\n";
}

Output yang Dihasilkan:

text
terlempar: Illuminate\Http\Client\RequestException
pesan exception: HTTP request returned status code 429:
{"pesan":"kuota habis"}

status via exception: 429

Perhatikan bahwa RequestException menyimpan response asli di property $e->response — pesan error, header, dan body tetap bisa dibaca lengkap dari dalam catch. Keluarga throw() menambah dua variasi: throwIf($kondisi) hanya melempar bila kondisi benar, dan throw() dengan callback yang berjalan tepat sebelum exception dilempar — tempat ideal mencatat log:

php
<?php

Http::fake(['api.example.com/cepat' => Http::response(['pesan' => 'oke'], 200)]);

$response = Http::get('https://api.example.com/cepat')->throwIf(false);
echo 'throwIf(false) status: '.$response->status()."\n";

Output yang Dihasilkan:

text
throwIf(false) status: 200

Untuk alur tanpa exception sama sekali, onError() menerima callback yang dijalankan hanya saat response gagal — response tetap dikembalikan untuk diproses manual:

php
<?php

Http::fake(['api.example.com/cepat' => Http::response(['pesan' => 'oke'], 200)]);

$pesan = 'belum terjadi apa-apa';
Http::get('https://api.example.com/cepat')->onError(function ($response) use (&$pesan) {
    $pesan = 'error '.$response->status();
});
echo 'pesan: '.$pesan."\n";

Output yang Dihasilkan:

text
pesan: belum terjadi apa-apa

Callback onError tidak pernah dijalankan karena response sukses — variabel $pesan tetap bernilai awalnya.

Pola try/catch Lengkap #

Di aplikasi nyata, dua jenis exception berbeda perlu ditangkap terpisah: ConnectionException berarti jaringan atau timeout bermasalah (request mungkin tidak pernah sampai), sedangkan RequestException berarti server menjawab dengan keberatan:

php
<?php

use Illuminate\Http\Client\ConnectionException;
use Illuminate\Http\Client\RequestException;
use Illuminate\Support\Facades\Http;

try {
    $response = Http::timeout(5)
        ->retry(2, 100)
        ->get('https://api.example.com/artikel')
        ->throw();

    echo 'berhasil: '.$response->json('pesan')."\n";
} catch (ConnectionException $e) {
    echo 'jaringan bermasalah: '.$e->getMessage()."\n";
} catch (RequestException $e) {
    echo 'API menolak: status '.$e->response->status()."\n";
}

Output yang Dihasilkan:

text
API menolak: status 429

Membaca satu response sudah kita kuasai. Berikutnya kita naik tingkat: mengonsumsi REST API sungguhan dengan pagination, filter, dan pemetaan ke model Eloquent — praktik lengkapnya di chapter Mengakses REST API . Rujukan semua method response ada di dokumentasi HTTP Client .