`symfony/http-client` is a powerful and flexible HTTP client library provided by the Symfony project. It is designed to be PSR-18 compliant, meaning it adheres to the standardized HTTP Client Interface, making it interchangeable with other PSR-18 compatible clients. Its primary purpose is to simplify making HTTP requests to external APIs, web services, or any other HTTP endpoint from within a PHP application.
Key features and capabilities include:
* Ease of Use: Provides a clean and intuitive API for sending various types of HTTP requests (GET, POST, PUT, DELETE, etc.).
* Asynchronous Requests: Supports sending multiple requests concurrently without blocking, significantly improving performance for applications making many external calls.
* Streaming Responses: Allows processing large responses chunk by chunk, reducing memory consumption.
* Retry Mechanism: Built-in support for automatically retrying failed requests with configurable policies.
* Mocking for Testing: Offers robust tools for mocking HTTP responses, making unit and integration testing of HTTP client usage straightforward and reliable.
* Error Handling: Provides clear exceptions and status codes for handling network issues, timeouts, and application-level errors (e.g., 4xx, 5xx responses). By default, calling `getContent()` on a response with a 4xx or 5xx status code will throw an exception.
* Request Options: Extensive options for configuring requests, including headers, query parameters, request bodies (form, JSON, multipart), timeouts, authentication, proxies, and more.
* Adapter Agnosticism: It can use various underlying HTTP client implementations (like cURL, PHP streams, or even custom adapters) depending on availability and configuration, providing flexibility and robustness.
* Integration: While a core component of the Symfony framework, it can be used as a standalone library in any PHP project.
In essence, `symfony/http-client` provides a modern, robust, and developer-friendly way to interact with HTTP-based services, handling many common challenges like network issues, retries, and asynchronous operations out of the box.
Example Code
```php
<?php
require 'vendor/autoload.php';
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
// Install via Composer:
// composer require symfony/http-client
// 1. Create an HTTP client instance
// For advanced configurations (e.g., base URI, default headers), use options:
// $client = HttpClient::create(['base_uri' => 'https://jsonplaceholder.typicode.com/', 'headers' => ['Accept' => 'application/json']]);
$client = HttpClient::create();
echo "--- Basic GET Request ---\n";
try {
// Make a GET request to a public API
$response = $client->request('GET', 'https://jsonplaceholder.typicode.com/posts/1');
// Get the HTTP status code (e.g., 200)
$statusCode = $response->getStatusCode();
// Get the content type (e.g., application/json). getHeaders() returns an associative array of arrays.
$contentType = $response->getHeaders()['content-type'][0];
// Get the response content as a string. This method throws exceptions for 4xx/5xx responses by default.
$content = $response->getContent();
echo "Status Code: {$statusCode}\n";
echo "Content Type: {$contentType}\n";
echo "Content (first 100 chars): " . substr($content, 0, 100) . "...\n\n";
// Decode JSON content
$data = json_decode($content, true);
echo "Decoded Title: {$data['title']}\n\n";
} catch (TransportExceptionInterface $e) {
// Catches network-related errors (e.g., host not found, connection refused)
echo "Transport Error: {$e->getMessage()}\n\n";
} catch (ClientExceptionInterface $e) {
// Catches 4xx HTTP client errors (e.g., 400 Bad Request, 404 Not Found)
echo "Client Error (4xx): {$e->getMessage()}\n\n";
} catch (RedirectionExceptionInterface $e) {
// Catches 3xx HTTP redirection errors (less common to catch explicitly)
echo "Redirection Error (3xx): {$e->getMessage()}\n\n";
} catch (ServerExceptionInterface $e) {
// Catches 5xx HTTP server errors (e.g., 500 Internal Server Error)
echo "Server Error (5xx): {$e->getMessage()}\n\n";
} catch (\Exception $e) {
// Catches any other unexpected exceptions
echo "An unexpected error occurred: {$e->getMessage()}\n\n";
}
echo "--- POST Request with JSON Body ---\n";
try {
$postData = [
'title' => 'foo',
'body' => 'bar',
'userId' => 1,
];
// Make a POST request. The 'json' option automatically sets Content-Type to application/json.
$response = $client->request('POST', 'https://jsonplaceholder.typicode.com/posts', [
'json' => $postData,
]);
$statusCode = $response->getStatusCode();
$content = $response->getContent();
echo "Status Code: {$statusCode}\n";
echo "Response Content: {$content}\n\n";
$responseData = json_decode($content, true);
echo "New Post ID: {$responseData['id']}\n\n";
} catch (TransportExceptionInterface $e) {
echo "Transport Error: {$e->getMessage()}\n\n";
} catch (ClientExceptionInterface $e) {
echo "Client Error (4xx): {$e->getMessage()}\n\n";
} catch (RedirectionExceptionInterface $e) {
echo "Redirection Error (3xx): {$e->getMessage()}\n\n";
} catch (ServerExceptionInterface $e) {
echo "Server Error (5xx): {$e->getMessage()}\n\n";
} catch (\Exception $e) {
echo "An unexpected error occurred: {$e->getMessage()}\n\n";
}
echo "--- GET Request with Error Handling (e.g., 404 Not Found) ---\n";
try {
// This endpoint typically returns 404 Not Found
$response = $client->request('GET', 'https://jsonplaceholder.typicode.com/posts/99999999999');
// When `getContent()` is called on a response with a 4xx or 5xx status code,
// it will throw a ClientExceptionInterface or ServerExceptionInterface.
// To avoid throwing and inspect the content manually, you can pass `false` to getContent().
if ($response->getStatusCode() >= 400) {
echo "Received status code: " . $response->getStatusCode() . "\n";
// getContent(false) prevents throwing an exception and returns the raw body
echo "Error message (if any): " . $response->getContent(false) . "\n\n";
} else {
echo "Content: " . $response->getContent() . "\n";
}
} catch (ClientExceptionInterface $e) {
// This specific exception is caught when getContent() is called on a 4xx response
echo "Client Error (4xx) caught for 404 example: {$e->getMessage()}\n";
echo "Response status code: {$e->getResponse()->getStatusCode()}\n";
echo "Response content: {$e->getResponse()->getContent(false)}\n\n";
} catch (TransportExceptionInterface $e) {
echo "Transport Error: {$e->getMessage()}\n\n";
} catch (RedirectionExceptionInterface $e) {
echo "Redirection Error (3xx): {$e->getMessage()}\n\n";
} catch (ServerExceptionInterface $e) {
echo "Server Error (5xx): {$e->getMessage()}\n\n";
} catch (\Exception $e) {
echo "An unexpected error occurred: {$e->getMessage()}\n\n";
}
?>
```








symfony/http-client