Увійти Реєстрація
Блог Серії
Кар'єра
Вакансії Компанії
Навчання
Документація Співбесіди Тестування Відео
Екосистема
Пакети Ресурси Проєкти Інструменти Події
Інше
Про нас Реклама

Senior: питання на співбесіді з теми «HTTP-клієнт»

Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.

2 питання

Через Http::pool() або Http::batch() - запити відправляються одночасно, загальний час близький до найдовшого, а не до суми.

$responses = Http::pool(fn (Pool $pool) => [
    $pool->as('rates')->timeout(3)->get('https://api.example.com/rates'),
    $pool->as('news')->timeout(3)->get('https://api.example.com/news'),
    $pool->as('weather')->timeout(3)->get('https://api.example.com/weather'),
]);

$rates = $responses['rates']->json();

batch() додає колбеки:

Http::batch(fn (Batch $batch) => [
    $batch->get('https://api.example.com/a'),
    $batch->get('https://api.example.com/b'),
])->then(fn (Batch $batch, array $results) => /* усі успішні */)
  ->catch(fn (Batch $batch, $key, $response) => /* один з помилкою */)
  ->send();   // або ->defer() - виконати після відповіді користувачу

Що враховувати:

  • кожен запит у пулі налаштовують окремо - спільні заголовки не успадковуються від зовнішнього виклику;
  • аргумент concurrency обмежує одночасні запити, щоб не впертися в ліміт стороннього API;
  • результат з помилкою - це Response з 5xx або виняток з'єднання в масиві, перевіряють кожен;
  • pool не замінює чергу: якщо результат не потрібен відповіді, краще поставити завдання.

Для паралельного виконання довільного PHP-коду, а не HTTP, - Concurrency::run().

Докладніше в документації: Паралельні запити

Виклики Http::... розкидані по контролерах - це однакові заголовки, таймаути й обробка помилок у двадцяти місцях і жодної можливості підмінити сервіс у тестах окремо від HTTP.

1. Базова конфігурація в одному місці - макрос:

// AppServiceProvider::boot()
Http::macro('github', fn () => Http::baseUrl('https://api.github.com')
    ->withToken(config('services.github.token'))
    ->acceptJson()
    ->timeout(5)
    ->retry(2, 200, throw: false));

2. Клієнт-клас з операціями предметної області:

final class GitHubClient
{
    public function stars(string $repo): int
    {
        return Http::github()->get("/repos/{$repo}")->throw()->json('stargazers_count');
    }
}

Код застосунку викликає stars('laravel/framework') і не знає про URL, заголовки й формат відповіді.

3. Свої DTO замість сирих масивів - формат API змінився, і правка в одному місці.

4. Наскрізні речі - глобальні middleware клієнта (Http::globalRequestMiddleware) для User-Agent чи кореляційного ID і подія ConnectionFailed для журналу.

5. Тести на двох рівнях: клієнт - через Http::fake() з реальними прикладами відповідей; решта коду - через підміну самого GitHubClient (інтерфейс і фейкова реалізація в контейнері).

Для великих API з десятками ендпойнтів беруть пакет Saloon - він формалізує саме цю структуру.

Докладніше в документації: Макроси