mirror of
https://github.com/coollabsio/coolify.git
synced 2026-08-24 10:05:47 -05:00
Add Nightwatch configuration guidance and MCP development skill docs across agent integrations, and refresh existing Laravel skill references.
3.6 KiB
3.6 KiB
HTTP Client Best Practices
Always Set Explicit Timeouts
The default timeout is 30 seconds — too long for most API calls. Always set explicit timeout and connectTimeout to fail fast.
Incorrect:
$response = Http::get('https://api.example.com/users');
Correct:
$response = Http::timeout(5)
->connectTimeout(3)
->get('https://api.example.com/users');
For service-specific clients, define timeouts in a macro:
Http::macro('github', function () {
return Http::baseUrl('https://api.github.com')
->timeout(10)
->connectTimeout(3)
->withToken(config('services.github.token'));
});
$response = Http::github()->get('/repos/laravel/framework');
Use Retry with Backoff for External APIs
External APIs have transient failures. Use retry() with increasing delays.
Incorrect:
$response = Http::post('https://api.stripe.com/v1/charges', $data);
if ($response->failed()) {
throw new PaymentFailedException('Charge failed');
}
Correct:
$response = Http::retry([100, 500, 1000])
->timeout(10)
->post('https://api.stripe.com/v1/charges', $data);
Only retry on specific errors:
$response = Http::retry(3, 100, function (Throwable $exception, PendingRequest $request) {
return $exception instanceof ConnectionException
|| ($exception instanceof RequestException && $exception->response->serverError());
})->post('https://api.example.com/data');
Handle Errors Explicitly
The HTTP Client does not throw on 4xx/5xx by default. Always check status or use throw().
Incorrect:
$response = Http::get('https://api.example.com/users/1');
$user = $response->json(); // Could be an error body
Correct:
$response = Http::timeout(5)
->get('https://api.example.com/users/1')
->throw();
$user = $response->json();
For graceful degradation:
$response = Http::get('https://api.example.com/users/1');
if ($response->successful()) {
return $response->json();
}
if ($response->notFound()) {
return null;
}
$response->throw();
Use Request Pooling for Concurrent Requests
When making multiple independent API calls, use Http::pool() instead of sequential calls.
Incorrect:
$users = Http::get('https://api.example.com/users')->json();
$posts = Http::get('https://api.example.com/posts')->json();
$comments = Http::get('https://api.example.com/comments')->json();
Correct:
use Illuminate\Http\Client\Pool;
$responses = Http::pool(fn (Pool $pool) => [
$pool->as('users')->get('https://api.example.com/users'),
$pool->as('posts')->get('https://api.example.com/posts'),
$pool->as('comments')->get('https://api.example.com/comments'),
]);
$users = $responses['users']->json();
$posts = $responses['posts']->json();
Fake HTTP Calls in Tests
Never make real HTTP requests in tests. Use Http::fake() and preventStrayRequests().
Incorrect:
it('syncs user from API', function () {
$service = new UserSyncService;
$service->sync(1); // Hits the real API
});
Correct:
it('syncs user from API', function () {
Http::preventStrayRequests();
Http::fake([
'api.example.com/users/1' => Http::response([
'name' => 'John Doe',
'email' => 'john@example.com',
]),
]);
$service = new UserSyncService;
$service->sync(1);
Http::assertSent(function (Request $request) {
return $request->url() === 'https://api.example.com/users/1';
});
});
Test failure scenarios too:
Http::fake([
'api.example.com/*' => Http::failedConnection(),
]);