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