Menghubungkan aplikasi ke API pihak ketiga dengan Symfony HttpClient: request GET/POST dengan headers & auth, mengelola timeout dan retry otomatis, streaming response besar, serta MockHttpClient untuk testing tanpa jaringan.

Aplikasi nyata jarang hidup sendiri — ia memanggil API pembayaran, geocoding, notifikasi push, atau service internal tim lain. Episode 11 memperkenalkan HttpClient, komponen Symfony untuk memanggil HTTP keluar dengan aman dan terkontrol.
Mengapa tidak memakai curl atau file_get_contents? Karena kebutuhan produksi lebih ketat: timeout yang tidak menggantung request, retry saat API sempat gagal, autentikasi yang rapi, dan kemampuan menulis test tanpa jaringan nyata. HttpClient menyediakan semuanya dengan API yang ringkas.
composer require symfony/http-clientDipanggil lewat DI seperti service lain:
use Symfony\Contracts\HttpClient\HttpClientInterface;
class WeatherService
{
public function __construct(
private readonly HttpClientInterface $client,
) {
}
public function current(string $city): array
{
$response = $this->client->request('GET', 'https://api.open-meteo.com/v1/forecast', [
'query' => ['latitude' => -6.2, 'longitude' => 106.8, 'current_weather' => true],
]);
if ($response->getStatusCode() >= 400) {
throw new \RuntimeException('Gagal mengambil cuaca');
}
return $response->toArray();
}
}Perhatikan toArray() — HttpClient mengurai JSON otomatis. Metode lain: toContent() (string mentah), toStream(), dan getContent().
Kebutuhan umum dikemas dalam opsi request:
$response = $this->client->request('POST', 'https://api.payment.example/charge', [
'headers' => ['Accept' => 'application/json'],
'auth_bearer' => $this->apiToken,
'json' => [
'amount' => 150000,
'currency' => 'IDR',
],
'timeout' => 10,
]);
$data = $response->toArray();| Opsi | Fungsi |
|---|---|
headers | Header custom |
auth_bearer | Token Bearer untuk Authorization |
auth_basic | Basic auth (['user', 'pass']) |
json / body | Body JSON otomatis / body mentah |
query | Query string parameter |
timeout | Batas waktu total (detik) |
max_redirects | Batas redirect otomatis |
Jangan pernah menaruh token di kode — simpan di env var (episode 16) atau secret vault.
API pihak ketiga kadang gagal sejenak (network blip, rate limit). Menangani retry manual di setiap pemanggilan itu rapuh dan berulang. Solusinya: pasang retry policy global di konfigurasi:
framework:
http_client:
retry_failed:
max_retries: 3
delay: 1000
multiplier: 2
max_delay: 10000Behavior default retry hanya untuk safe methods (GET) dan error transien (TimeoutException, 5xx, 429). Retry tidak dipicu untuk 4xx selain 429 — menghindari menggandakan request yang memang salah. Kita bahas penyesuaian per-request di bagian mocking/test nanti.
Untuk response besar (download file, output panjang), jangan tampung di memory — stream langsung:
use Symfony\Component\Console\Output\ConsoleOutputInterface;
$response = $this->client->request('GET', 'https://example.com/laporan.zip');
$file = new \SplFileObject('/tmp/laporan.zip', 'w');
foreach ($this->client->stream($response) as $chunk) {
$file->fwrite($chunk->getContent());
}$client->stream() mengembalikan chunks seiring data datang — memory usage tetap rendah walau file ratusan MB. Ini juga dipakai untuk progress bar di CLI command (episode 9).
Di project yang memanggil banyak API, setiap API layak punya named client dengan konfigurasi sendiri:
framework:
http_client:
scoped_clients:
payment.client:
base_uri: 'https://api.payment.example/'
auth_bearer: '%env(PAYMENT_TOKEN)%'
timeout: 8
geo.client:
base_uri: 'https://nominatim.openstreetmap.org/'
headers: { 'User-Agent': 'my-app' }
timeout: 15Named client di-inject dengan nama service payment.client dan geo.client — masing-masing dengan default-nya sendiri. Controller/command cukup memanggil method, tanpa tahu detail transport.
Test tidak boleh bergantung pada API eksternal yang tidak pasti. Gunakan MockHttpClient untuk mengganti transport:
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\Response\MockResponse;
$mock = new MockHttpClient([
new MockResponse(
json_encode(['temperature' => 29.5]),
['http_code' => 200, 'response_headers' => ['content-type' => 'application/json']],
),
]);
$service = new WeatherService($mock);
self::assertSame(29.5, $service->current('Jakarta')['temperature']);MockHttpClient mengikuti interface HttpClientInterface yang sama — jadi service kalian bisa di-test tanpa jaringan, dan test tetap cepat serta deterministik. Pola ini dipakai kembali di episode 17 (testing penuh).
Tip
Untuk API yang dipanggil berkali-kali, kombinasikan HttpClient dengan cache (episode 14): hasil geocoding untuk koordinat yang sama tidak perlu dipanggil ulang. Cache di depan HTTP call adalah optimasi termudah yang sering diabaikan.
getContent()/toArray() yang memicu transfer. Selalu baca response.query atau header yang ikut tercatat log request.Pada episode 11 ini, kalian telah menghubungkan aplikasi ke dunia luar.
Inti yang harus dibawa pulang:
HttpClientInterface menyediakan request() dengan opsi: headers, auth, json, query, timeout.retry_failed — aman untuk GET & error transien.$client->stream()) untuk response besar tanpa boros memory.Di episode 12 selanjutnya kita mengamankan akses: Security: Authentication & Authorization — authenticator & login form, password hashing, roles & access control, API token, dan voters untuk otorisasi granular. Sampai jumpa di episode 12!