symfony/http-client
Symfony HttpClient provides a modern API to fetch HTTP resources synchronously or asynchronously. Supports efficient streaming, retries, and multiple transports, making it easy to integrate robust HTTP requests into Symfony or any PHP app.
Install the package via Composer:
composer require symfony/http-client
Initialize the client in a Laravel service provider or directly in a class:
use Symfony\Contracts\HttpClient\HttpClientInterface;
use Symfony\HttpClient\HttpClient;
public function register()
{
$this->app->singleton(HttpClientInterface::class, function ($app) {
return HttpClient::create([
'timeout' => 30, // seconds
'base_uri' => 'https://api.example.com/v1/',
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer ' . $app['auth']->token(),
],
]);
});
}
use Symfony\Contracts\HttpClient\ResponseInterface;
public function fetchData(HttpClientInterface $client)
{
$response = $client->request('GET', '/users');
// Get JSON response
$users = $response->toArray();
// Or stream the response
$response->toStreamingIterator(function ($chunk) {
// Process chunk
});
}
request(), get(), post(), etc., for different HTTP methods.toArray(), toStream(), or getContent() based on needs.Leverage decorators for middleware-like behavior (e.g., logging, caching, retries):
use Symfony\Component\HttpClient\RetryClient;
use Symfony\Component\HttpClient\CachingHttpClient;
use Symfony\Component\HttpClient\Middleware\LoggerMiddleware;
$client = HttpClient::create();
$client = new RetryClient($client, [
'max_retries' => 3,
'delay' => 100,
'max_delay' => 1000,
'methods' => ['GET', 'POST'],
'statusCodes' => [503],
]);
$client = new CachingHttpClient($client, new FilesystemCache('/path/to/cache'));
$client = $client->withOptions(['headers' => ['X-Custom-Header' => 'value']]);
Use async() for non-blocking requests:
$promise = $client->requestAsync('GET', '/data');
$response = $promise->await(); // Blocking wait
// OR
$promise->then(function (ResponseInterface $response) {
// Handle response asynchronously
});
Process large responses in chunks:
$response = $client->stream('GET', '/large-file');
$response->toStreamingIterator(function ($chunk) {
file_put_contents('output.txt', $chunk, FILE_APPEND);
});
Configure retries for transient failures:
$retryClient = new RetryClient($client, [
'max_retries' => 3,
'delay' => 200,
'methods' => ['GET', 'POST', 'PUT', 'DELETE'],
'statusCodes' => [429, 500, 502, 503, 504],
]);
Use ScopingHttpClient for dynamic base URIs:
$scopedClient = new ScopingHttpClient($client, 'https://api.example.com/v2/');
$response = $scopedClient->request('GET', '/users'); // Full URL: https://api.example.com/v2/users
Http facade for seamless integration with Laravel's request lifecycle.HttpClientInterface in tests using Mockery or Laravel's MockHttpClient.Connection Pooling:
CurlHttpClient instances across requests can lead to connection leaks or timeouts.HttpClient::create() with default settings or configure max_host_connections:
HttpClient::create(['max_host_connections' => 10]);
Streaming Quirks:
$response = $client->stream('GET', '/stream');
$response->toStreamingIterator(function ($chunk) {
if ($chunk === null) {
// Handle delayed stream
}
});
Caching Headers:
CachingHttpClient may not respect Cache-Control headers correctly if decorators are misordered.CachingHttpClient after UriTemplate and ScopingHttpClient:
$client = new CachingHttpClient(
new ScopingHttpClient(
new UriTemplateHttpClient($baseClient),
'https://api.example.com/'
),
$cache
);
Async Response Decoration:
AsyncResponse decorators can cause issues (fixed in v8.0.5).Timeout Handling:
try {
$response = $client->request('GET', '/slow-endpoint', ['timeout' => 5]);
} catch (TransportExceptionInterface $e) {
// Handle timeout
}
HTTP/3 with Proxies:
HttpClient::create(['options' => ['http_version' => '1.1']]);
$client = HttpClient::create(['logger' => function ($level, $message, array $context = []) {
\Log::debug($message, $context);
}]);
$response = $client->request('GET', '/endpoint', [
'headers' => ['X-Debug' => 'true'],
]);
\Log::debug('Response Headers:', $response->getHeaders());
\Log::debug('Response Body:', $response->getContent(false));
copyAsCurl() for Debugging:
$curl = $client->copyAsCurl('GET', '/endpoint');
\Log::debug('cURL Command:', $curl);
Custom Middleware: Create middleware to modify requests/responses:
use Symfony\Component\HttpClient\Middleware\BaseMiddleware;
class CustomHeaderMiddleware extends BaseMiddleware
{
public function __invoke(Request $request, callable $next, callable $first = null)
{
$request = $request->withHeader('X-Custom-Header', 'value');
return $next($request);
}
}
Apply it via:
$client = HttpClient::create(['middlewares' => [new CustomHeaderMiddleware()]]);
Event Listeners: Use Symfony’s event system for advanced control:
$client = HttpClient::create();
$client->on('request', function (Request $request) {
\Log::debug('Request:', $request->getUri());
});
$client->on('response', function (Response $response) {
\Log::debug('Status:', $response->getStatusCode());
});
Custom Transport:
Implement TransportInterface for specialized needs (e.g., custom proxy logic):
use Symfony\Component\HttpClient\Transport\TransportInterface;
class CustomTransport implements TransportInterface
{
public function sendRequest(Request $request): Response
{
// Custom logic
}
}
Use it via:
$client = HttpClient::create(['transport' => new CustomTransport()]);
$this->app->singleton(HttpClientInterface::class, function ($app) {
$config = $app['config']['http_client'];
return HttpClient::create($config['options'] ?? []);
});
How can I help you explore Laravel packages today?