Calling other services
Payments, delivery, exchange rates, social login — an application talks to other people's APIs all the time. Laravel has the Http facade for that: a short way to write requests and easy faking of responses in tests.
A GET request
use Illuminate\Support\Facades\Http;
$response = Http::get('https://api.example.com/rates', [
'base' => 'EUR',
]);
$rates = $response->json('rates');The second argument holds the address parameters. The json() method parses the response, and with an argument returns the value under a key.
What a response offers
| Method | What it returns |
|---|---|
json() | The parsed JSON |
body() | The body as a string |
status() | The status code |
successful() | true for 2xx codes |
failed() | true for 4xx and 5xx codes |
header('Name') | A header value |
A POST request
$response = Http::post('https://api.example.com/orders', [
'product_id' => 42,
'quantity' => 2,
]);
$orderId = $response->json('id');The data is sent as JSON. For a regular form add asForm().
Headers and authorization
$response = Http::withToken(config('services.shop.token'))
->withHeaders(['X-Request-Id' => (string) Str::uuid()])
->acceptJson()
->get('https://api.example.com/me');Timeouts and retries
$response = Http::timeout(5)
->retry(3, 200)
->get('https://api.example.com/rates');timeout(5) limits the wait to five seconds. retry(3, 200) repeats the request up to three times with a 200 millisecond pause if the service did not answer.
Errors
By default a response with code 500 raises no exception — it is easy to miss. The throw() method turns an error into an exception:
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Http\Client\RequestException;
try {
$rates = Http::timeout(5)
->get('https://api.example.com/rates')
->throw()
->json('rates');
} catch (RequestException $e) {
report($e); // the service answered with an error
} catch (ConnectionException $e) {
report($e); // the service is unavailable
}A configured client
The common settings of one API are set once — in a provider:
Http::macro('shop', function () {
return Http::baseUrl('https://api.example.com')
->withToken(config('services.shop.token'))
->timeout(5);
});$products = Http::shop()->get('/products')->json();Faking in tests
Tests must not call the real service. Http::fake() returns prepared responses:
Http::fake([
'api.example.com/rates*' => Http::response(['rates' => ['USD' => 1.08]], 200),
]);
$this->get('/prices')->assertSee('1.08');
Http::assertSent(fn ($request) => $request->url() === 'https://api.example.com/rates?base=EUR');Common mistake
Without timeout() a request to a hung service keeps the page open for up to thirty seconds, and under a rush of visitors stops the whole site. Always set a timeout and decide in advance what to show on failure. Slow calls whose result is not needed right away go to a queue.