Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Запросы к другим сервисам

Оплата, доставка, курсы валют, вход через соцсети — приложение постоянно обращается к чужим 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() запрос к зависшему сервису держит страницу открытой до тридцати секунд, а при наплыве посетителей останавливает весь сайт. Всегда задавайте время ожидания и решайте заранее, что показать при сбое. Медленные обращения, результат которых не нужен сразу, отправляйте в очередь.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.