Belajar Symfony - HTTP Client & HttpClient
Episode 11 of 27

Belajar Symfony - HTTP Client & HttpClient

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.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

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.

Instalasi dan Request Pertama

Install HttpClient
composer require symfony/http-client

Dipanggil lewat DI seperti service lain:

Request GET pertama
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().

Headers, Auth, dan Timeout

Kebutuhan umum dikemas dalam opsi request:

Opsi request lengkap
$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();
OpsiFungsi
headersHeader custom
auth_bearerToken Bearer untuk Authorization
auth_basicBasic auth (['user', 'pass'])
json / bodyBody JSON otomatis / body mentah
queryQuery string parameter
timeoutBatas waktu total (detik)
max_redirectsBatas redirect otomatis

Jangan pernah menaruh token di kode — simpan di env var (episode 16) atau secret vault.

Retry Otomatis

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:

config/packages/http_client.yaml
framework:
    http_client:
        retry_failed:
            max_retries: 3
            delay: 1000
            multiplier: 2
            max_delay: 10000

Behavior 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.

Streaming Response

Untuk response besar (download file, output panjang), jangan tampung di memory — stream langsung:

Streaming ke file
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).

Konfigurasi Global dan Named Clients

Di project yang memanggil banyak API, setiap API layak punya named client dengan konfigurasi sendiri:

Named clients
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: 15

Named 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.

Mocking untuk Testing

Test tidak boleh bergantung pada API eksternal yang tidak pasti. Gunakan MockHttpClient untuk mengganti transport:

Test dengan MockHttpClient
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.

Common Pitfalls

  • Response tidak di-consume — HttpClient bersifat lazy; getContent()/toArray() yang memicu transfer. Selalu baca response.
  • Timeout terlalu kecil/longgar — default 30 detik; atur sesuai ekspektasi API.
  • Auth bocor di log — hindari memasukkan token ke dalam query atau header yang ikut tercatat log request.

Penutup

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 otomatis global via retry_failed — aman untuk GET & error transien.
  • Streaming ($client->stream()) untuk response besar tanpa boros memory.
  • Named clients per API dengan base_uri & default masing-masing.
  • MockHttpClient membuat test bebas jaringan dan deterministik.

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!

Belajar Symfony - HTTP Client & HttpClient | Belajar Symfony