Calling other services
Exchange rates, payments, delivery, social login — a site talks to other people's APIs all the time. Symfony has the HttpClient component for that: it sends requests and parses responses.
A GET request
use Symfony\Contracts\HttpClient\HttpClientInterface;
#[Route('/rates', name: 'rates')]
public function rates(HttpClientInterface $client): Response
{
$response = $client->request('GET', 'https://api.example.com/rates');
$data = $response->toArray();
return $this->render('rates.html.twig', ['rates' => $data['rates']]);
}toArray() turns a JSON response into an array.
What a response tells you
| Method | What it returns |
|---|---|
getStatusCode() | The status code |
getHeaders() | The headers |
getContent() | The body as a string |
toArray() | The parsed JSON |
Address parameters
$response = $client->request('GET', 'https://api.example.com/users', [
'query' => ['page' => 2, 'role' => 'admin'],
]);The address becomes /users?page=2&role=admin, with the values encoded.
A POST request
$response = $client->request('POST', 'https://api.example.com/orders', [
'json' => ['product_id' => 42, 'quantity' => 2],
]);
$order = $response->toArray();The json key encodes the data and adds the Content-Type header. A regular form uses the body key.
Headers and authorization
$response = $client->request('GET', 'https://api.example.com/me', [
'auth_bearer' => $token,
'headers' => ['Accept' => 'application/json'],
'timeout' => 5,
]);timeout limits the wait: without it a slow service holds up your page too.
Errors
If the service answers with a 4xx or 5xx code, toArray() and getContent() throw an exception. A network failure is an exception as well:
use Symfony\Contracts\HttpClient\Exception\HttpExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
try {
$data = $client->request('GET', $url)->toArray();
} catch (HttpExceptionInterface $e) {
$code = $e->getResponse()->getStatusCode();
// the service answered with an error
} catch (TransportExceptionInterface $e) {
// the service is unavailable
}A scoped client
The common parameters of one API are set in the configuration:
# config/packages/framework.yaml
framework:
http_client:
scoped_clients:
github.client:
base_uri: 'https://api.github.com'
headers:
Accept: 'application/vnd.github+json'
Authorization: 'Bearer %env(GITHUB_TOKEN)%'The argument name selects the client:
public function __construct(private HttpClientInterface $githubClient) {}
public function repos(string $user): array
{
return $this->githubClient->request('GET', "/users/$user/repos")->toArray();
}Common mistake
A request is sent not when request() is called but when you access the response. If you never call getStatusCode(), getContent() or toArray(), a service error goes unnoticed until the object is destroyed. Always read the response and wrap a call to someone else's service in try: sooner or later it will be unavailable.