Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

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

MethodWhat 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.

Thanks for reading!

Donate to the site — we work hard for you.