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 - він формалізує саме цю структуру.