weblabel/http-client
Weblabel HTTP Client offers a simple, developer-friendly way to send HTTP requests and handle responses in Laravel and PHP applications. It wraps common client functionality behind a clean API for building integrations.
Verify it installs before you read any further. The package was last tagged 2021-12-08, so its composer.json almost certainly pins illuminate/support and guzzlehttp/guzzle to constraints from the Laravel 8/9 era. Run a dry run against your actual app first:
composer require weblabel/http-client --dry-run -W
If that resolves cleanly, install it, then read the source in this order — do not trust the README alone:
composer.json — the require block tells you the real supported Laravel/PHP/Guzzle range.src/*ServiceProvider.php) — look for mergeConfigFrom(), container bindings in register(), and whether the client is bound as a singleton or resolved fresh.Illuminate\Support\Facades\Http, a raw Guzzle wrapper, or both? This determines everything about testing.config/http-client.php or similar) — base URL, timeout, headers, auth.First use case: pick one narrow outbound integration — a single third-party API call inside a queued job — and route only that through the wrapper. Do not migrate your existing Http:: calls to it. The goal of the first pass is to learn whether the wrapper adds anything (retry policy, logging, auth injection, response mapping) beyond what the framework already gives you.
If you're on Laravel 7+, benchmark against what you already have before committing. Laravel's Http facade already ships retries, macros, Http::fake(), and connection-level config. The bar for a third-party wrapper in 2021+ is high.
Resolve from the container, never new it up. Whatever the wrapper is, you want to bind it and swap it in tests. If the package registers a binding, type-hint the interface/class in your constructor. If it doesn't, add your own binding in AppServiceProvider:
$this->app->singleton(Weblabel\HttpClient\Client::class, fn ($app) => new Weblabel\HttpClient\Client(
config('services.vendor.base_url'),
config('services.vendor.token'),
));
Wrap the wrapper. Put a domain-specific class between your application and the package:
final class BillingApi
{
public function __construct(private Weblabel\HttpClient\Client $http) {}
public function invoice(string $id): InvoiceData
{
$response = $this->http->get("/invoices/{$id}");
return InvoiceData::from($response->json());
}
}
This insulates you from the package being abandoned (which, at 0 stars and no release since 2021, is the base case). If you ever need to rip it out, you change one class.
Drive configuration from config/services.php, not the package config file. Published package configs get stale and are easy to forget during a config:cache. Keep credentials in services.php reading from env(), and pass them into the client at binding time.
Testing. This is the make-or-break question. If the wrapper delegates to Laravel's Http facade internally, Http::fake() works and you're fine. If it holds a Guzzle ClientInterface, inject a MockHandler:
$mock = new GuzzleHttp\Handler\MockHandler([
new GuzzleHttp\Psr7\Response(200, [], json_encode(['id' => 1])),
]);
$client = new Weblabel\HttpClient\Client(new GuzzleHttp\Client(['handler' => $mock]));
If neither injection point exists, you're reduced to Http::fake() on the underlying facade and hoping — a strong signal to skip the package.
Adopt by fork, not by tag. Given the release age, if you decide to use it, pin to a commit and vendor it via a VCS or path repository in composer.json:
"repositories": [{"type": "vcs", "url": "https://github.com/weblabel-tech/http-client"}]
That way you can patch PHP 8.2+ deprecations or Guzzle 8 breakage yourself without waiting for a maintainer who hasn't shipped since 2021.
"${var}" string interpolation (deprecated in 8.2). Grep for both in src/ before deploying to a modern runtime.guzzlehttp/guzzle: ^7 and your app later moves to Guzzle 8, you'll be stuck or forced to fork. Check the constraint.config:cache + env(). If the package calls env() from inside a class rather than from a config file, those values become null once you cache config in production. This is the single most common "works locally, breaks in prod" failure with small wrapper packages.Http::throw()). Read the error path carefully — confirm whether you get exceptions or just a status code you might ignore.Cannot rewind a stream.Log::debug() middleware in, or if you can reach the Guzzle handler stack, push() a Middleware::history() and dump it on failure. If the package seals the stack, you're back to fork-and-patch.Http facade with macros and Http::fake(). Reach for this package only if you are inheriting an application already on it — and even then, budget a sprint to migrate off.How can I help you explore Laravel packages today?