Запросы к другим сервисам
Оплата, доставка, курсы валют, вход через соцсети — приложение постоянно обращается к чужим API. В Laravel для этого есть фасад Http: короткая запись запросов и удобная подмена ответов в тестах.
Запрос GET
use Illuminate\Support\Facades\Http;
$response = Http::get('https://api.example.com/rates', [
'base' => 'EUR',
]);
$rates = $response->json('rates');Второй аргумент — параметры адреса. Метод json() разбирает ответ, а с аргументом возвращает значение по ключу.
Что есть у ответа
| Метод | Что возвращает |
|---|---|
json() | Разобранный JSON |
body() | Тело ответа строкой |
status() | Код состояния |
successful() | true для кодов 2xx |
failed() | true для кодов 4xx и 5xx |
header('Name') | Значение заголовка |
Запрос POST
$response = Http::post('https://api.example.com/orders', [
'product_id' => 42,
'quantity' => 2,
]);
$orderId = $response->json('id');Данные отправляются в формате JSON. Для обычной формы добавьте asForm().
Заголовки и авторизация
$response = Http::withToken(config('services.shop.token'))
->withHeaders(['X-Request-Id' => (string) Str::uuid()])
->acceptJson()
->get('https://api.example.com/me');Время ожидания и повторы
$response = Http::timeout(5)
->retry(3, 200)
->get('https://api.example.com/rates');timeout(5) ограничивает ожидание пятью секундами. retry(3, 200) повторит запрос до трёх раз с паузой 200 миллисекунд, если сервис не ответил.
Ошибки
По умолчанию ответ с кодом 500 не вызывает исключения — его легко не заметить. Метод throw() превращает ошибку в исключение:
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Http\Client\RequestException;
try {
$rates = Http::timeout(5)
->get('https://api.example.com/rates')
->throw()
->json('rates');
} catch (RequestException $e) {
report($e); // сервис ответил ошибкой
} catch (ConnectionException $e) {
report($e); // сервис недоступен
}Настроенный клиент
Общие настройки одного API задают один раз — в провайдере:
Http::macro('shop', function () {
return Http::baseUrl('https://api.example.com')
->withToken(config('services.shop.token'))
->timeout(5);
});$products = Http::shop()->get('/products')->json();Подмена в тестах
Тесты не должны обращаться к настоящему сервису. Http::fake() возвращает заготовленные ответы:
Http::fake([
'api.example.com/rates*' => Http::response(['rates' => ['USD' => 1.08]], 200),
]);
$this->get('/prices')->assertSee('1.08');
Http::assertSent(fn ($request) => $request->url() === 'https://api.example.com/rates?base=EUR');Частая ошибка
Без timeout() запрос к зависшему сервису держит страницу открытой до тридцати секунд, а при наплыве посетителей останавливает весь сайт. Всегда задавайте время ожидания и решайте заранее, что показать при сбое. Медленные обращения, результат которых не нужен сразу, отправляйте в очередь.