Skip to content

Files

Latest commit

Jun 10, 2025
99f0fd8 Β· Jun 10, 2025

History

History
336 lines (242 loc) Β· 11.2 KB

api-and-http-client.md

File metadata and controls

336 lines (242 loc) Β· 11.2 KB

API & The HTTP Client Tips (cd ..)

Laravel Tip πŸ’‘: The "withToken()" method (⬆️)

Laravel

Did you know that the Laravel HTTP Client comes with a fluent method called "withToken()" that you can use to set bearer tokens? πŸš€

<?php

// The following code
Http::withHeaders([
    'Authorization' => 'Bearer eyJhbGciOiJIUz...',
]);

// Is equivalent to this
Http::withToken('eyJhbGciOiJIUz...');

Laravel Tip πŸ’‘: Extend the "PersonalAccessToken" model (⬆️)

Laravel

Sanctum is a powerful package for managing API tokens. Sometimes you may wish the token model had more methods. Well, guess what? You can extend the model and register your custom one instead! πŸš€

<?php
use App\Models\Sanctum\PersonalAccessToken;
use Laravel\Sanctum\Sanctum;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    // Custom token model that adds new methods such as "lastUsedAt()"
    Sanctum::usePersonalAccessTokenModel(PersonalAccessToken::class);
}

// Now this will return an instance of the custom model
$token = $request->user()->currentAccessToken();

Laravel Tip πŸ’‘: HTTP Client Handler Stats (⬆️)

Laravel

The Laravel HTTP Client uses Guzzle under the hood, providing access to statistics for each request you make, including total time, download speed and much more πŸš€

<?php

$stats = Http::get('https://oussama-mater.tech')->handlerStats();

/*
All the statistics related to the request:
[
    "http_code" => 200
    "total_time" => 8.430478
    "speed_download" => 135.0
    "speed_upload" => 0.0
    ...
]
*/

Laravel Tip πŸ’‘: Without Data Wrapping (⬆️)

Laravel

Eloquent API resources are automatically wrapped in a "data" object. Sometimes, you may want to remove this wrapping. Laravel includes the "withoutWrapping" method to do exactly that πŸš€

<?php

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        JsonResource::withoutWrapping();
    }
}

/*
[
    {
        "id": 1,
        "name": "Eladio Schroeder Sr.",
        "email": "therese28@example.com"
    },
    {
        "id": 2,
        "name": "Liliana Mayert",
        "email": "evandervort@example.com"
    }
]
*/

Laravel Tip πŸ’‘: Collect API Responses (⬆️)

Laravel

Usually, when working with the HTTP Client, we manually collect the JSON response from the API. However, did you know that Laravel ships with the "collect" method directly on the HTTP Client? πŸš€

<?php

use Illuminate\Support\Facades\Http;

// Instead of this πŸ˜’
$response = Http::get('http://example.com')->json();
collect($response);

// Do this 😎
$collection = Http::get('http://example.com')->collect();

Laravel Tip πŸ’‘: A Better Content Negotiation (⬆️)

Laravel

Sometimes you might have multiple response formats that you return. You can use the "getAcceptableContentTypes" method to map your response to what's best for the user πŸš€

<?php

request()->getAcceptableContentTypes();

// [
//     0 => "text/html",
//     1 => "application/xhtml+xml",
//     2 => "image/avif",
//     3 => "image/webp",
//     4 => "image/apng",
//     5 => "application/xml",
//     6 => "x/e",
//     7 => "application/signed-exchange",
// ];

Laravel Tip πŸ’‘: Get Bearer Tokens Elegantly (⬆️)

Laravel

Building an API with Laravel? You can retrieve the bearer token using the "bearerToken" method on the request object without having to manually parse it πŸš€

<?php

// Instead of this 😞
$token = substr(request()->header('Authorization'), 7);

// Do this 😊
$token = request()->bearerToken();

Laravel Tip πŸ’‘: Retry Concurrent Requests (⬆️)

Laravel

In Laravel versions 10 and below, retrying failed concurrent requests wasn't possible. Well, guess what? In Laravel 11, we can! πŸš€

<?php

use Illuminate\Http\Client\Pool;
use Illuminate\Support\Facades\Http;

$responses = Http::pool(fn (Pool $pool) => [
    $pool->as('first')->retry(2)->get('http://localhost/first'),
    $pool->as('second')->retry(2)->get('http://localhost/second'),
    $pool->as('third')->retry(2)->get('http://localhost/third'),
]);

Laravel Tip πŸ’‘: Send Concurrent Requests (⬆️)

Laravel

Laravel's HTTP client wraps Guzzle, which allows you to make concurrent requests to speed things up. This is very helpful for various cases, such as health checks! πŸš€

<?php

use Illuminate\Http\Client\Pool;
use Illuminate\Support\Facades\Http;

$responses = Http::pool(fn (Pool $pool) => [
    $pool->get('http://localhost/first'),
    $pool->get('http://localhost/second'),
    $pool->get('http://localhost/third'),
]);

return $responses[0]->ok() &&
       $responses[1]->ok() &&
       $responses[2]->ok();

Laravel Tip πŸ’‘: URI Templates (⬆️)

Laravel

Since Laravel uses Guzzle under the hood, you can use URI templates with Laravel's HTTP Client by calling the "withUrlParameters" method πŸš€

<?php

// This follows the URI Template specification (RFC 6570).
Http::withUrlParameters([
    'endpoint' => 'https://laravel.com',
    'page' => 'docs',
    'version' => '11.x',
    'topic' => 'validation',
])->get('{+endpoint}/{page}/{version}/{topic}');

Laravel Tip πŸ’‘: Global Middleware for HTTP Client (⬆️)

Laravel

Sometimes you may want to apply global headers to all outgoing requests. For instance, a global user agent can help you identify your app's requests in other services or third-party APIs. Laravel already supports request and response middleware to do exactly that πŸš€

<?php

use Illuminate\Support\Facades\Http;

Http::globalRequestMiddleware(fn ($request) => $request->withHeader(
    'User-Agent', 'Example Application/1.0'
));

Http::globalResponseMiddleware(fn ($response) => $response->withHeader(
    'X-Finished-At', now()->toDateTimeString()
));

Laravel Tip πŸ’‘: Convert Responses to Exceptions (⬆️)

Laravel

When consuming APIs, your request might fail. While you can manually check and throw exceptions, Laravel ships with handy helpers to do exactly that πŸš€

<?php

// Instead of this πŸ₯±
if ($response->clientError()) {
    throw new RequestException($response);
}

if ($response->serverError()) {
    throw new RequestException($response);
}

if ($response->failed()) {
    throw new RequestException($response);
}

// You can do this 😎
$response->throwIfClientError(); // >=400 & <500

$response->throwIfServerError(); // >= 500

// You can set an exact status
$response->throwIfStatus(403);

// Or even specify a range πŸ”₯
$response->throwIfStatus(fn(int $status) => $status >= 400);

Laravel Tip πŸ’‘: HTTP Response Status Helpers (⬆️)

Laravel

When making API requests, you often need to check the response status code. While you can do this manually, Laravel provides wrappers for almost all status codes, which you can use for elegant and readable checks πŸš€

<?php

use Illuminate\Support\Facades\Http;

$response = Http::get('https://blog.oussama-mater.tech');

// Instead of checking the status manually πŸ₯±
$response->status() === 404;

// You can do this πŸ”₯
$response->notFound(); // status code 404
$response->tooManyRequests(); // status code 429
$response->forbidden(); // status code 403
$response->unauthorized(); // status code 401
$response->unprocessableContent(); // status code 422
$response->serverError(); // status code >= 500
$response->clientError(); // status code >= 400 && <500

Laravel Tip πŸ’‘: Real-Time Download Progress (⬆️)

Laravel

If you ever need to download a file in your Laravel app, consider using Guzzle's "progress" option. It gives you real-time updates on the download, which you can broadcast to your UI, display in the console, or handle however you like πŸš€

<?php

use Illuminate\Support\Facades\Http;

Http::withToken('an-api-token')
    ->get('https://api.example.com/plugins/some-theme')
    ->timeout(30)
    ->withOptions([
        'sink' => storage_path('plugins/some-theme.zip'),
        'progress' => function ($downloadTotal, $downloadedBytes) {
            // You can emit an event to the frontend for real-time updates,
            event(new PluginDownloadProgress($downloadedBytes, $downloadTotal));
            // Or update a progress bar in a console command, etc..
        }
    ]);