Laravel cookbook · Beginner

Call external APIs with timeouts, retries and fakes

Calls to a partner API hang, fail on temporary errors, and make tests depend on the network.

Create a free account to save this page, take notes and track your progress. Sign in

Approach

Configure the HTTP client with a base URL, token, timeouts and retries with backoff for connection errors and 5xx responses only. In tests, fake responses and assert what was sent.

Solution

<?php
// app/Services/ShippingClient.php
namespace App\Services;

use Illuminate\Http\Client\ConnectionException;
use Illuminate\Http\Client\RequestException;
use Illuminate\Support\Facades\Http;

class ShippingClient
{
    public function quote(string $country, int $weightGrams): int
    {
        return Http::baseUrl(config('services.shipping.url'))
            ->withToken(config('services.shipping.token'))
            ->acceptJson()
            ->connectTimeout(2)
            ->timeout(5)
            ->retry([200, 500, 1000], when: fn ($e) => $e instanceof ConnectionException
                || ($e instanceof RequestException && $e->response->serverError()))
            ->get('/quotes', ['country' => $country, 'weight' => $weightGrams])
            ->throw()
            ->json('price_cents');
    }
}
<?php
// in a test
use Illuminate\Http\Client\Request;
use Illuminate\Support\Facades\Http;

Http::fake([
    'shipping.example.com/quotes*' => Http::sequence()->pushStatus(503)->push(['price_cents' => 990]),
]);

$price = app(\App\Services\ShippingClient::class)->quote('DE', 1200);

Http::assertSentCount(2);
Http::assertSent(fn (Request $request) => $request['country'] === 'DE');

Pitfalls

  • No timeout: a slow partner ties up PHP workers until the server's limit.
  • Retrying non-idempotent POSTs (payments) without an idempotency key.
  • Retrying 4xx errors, which won't succeed on retry.

Variations

  • Register a macro (Http::macro('shipping', ...)) to reuse the configured client.
  • Call Http::preventStrayRequests() in tests so unfaked requests fail.

Further reading: HTTP client

Reference: https://laravel.com/docs/13.x/http-client

More Laravel recipes

Was this page helpful?