Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Httplug Laravel Package

php-http/laravel-httplug

Laravel integration for HTTPlug that wires PSR-7/PSR-18 HTTP clients into the service container, provides package configuration and convenient Laravel access, and lets apps use interchangeable HTTPlug adapters for outbound HTTP requests.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Install an adapter alongside the package. HTTPlug is only an abstraction — it ships no transport. You always need at least one adapter:

composer require php-http/laravel-httplug php-http/guzzle6-adapter
# alternatives: php-http/curl-client, php-http/react-adapter, php-http/socket-client

2. Register the service provider. On Laravel 5.4 and earlier, add it to the providers array in config/app.php. On 5.5+, check the package's composer.json for extra.laravel.providers (package discovery) — but with a 2016 release, verify manually rather than assuming discovery works.

3. Publish the config. Run php artisan vendor:publish, select the httplug entry, and inspect config/httplug.php. This is where you choose the adapter/driver and any client options. Read this file first — it is the authoritative source for what the package actually wires up.

4. Resolve the client. The provider binds the HTTPlug interfaces into the container, so anywhere you can type-hint:

use Http\Client\HttpClient;
use Http\Message\MessageFactory;

class PingController extends Controller
{
    public function __construct(private HttpClient $http, private MessageFactory $factory) {}

    public function __invoke()
    {
        $request  = $this->factory->createRequest('GET', 'https://example.com/health');
        $response = $this->http->sendRequest($request);

        return response($response->getBody()->getContents(), $response->getStatusCode());
    }
}

5. First real use case. Replace a hard-coded new GuzzleHttp\Client() (or a facade call) with a type-hinted Http\Client\HttpClient. You immediately gain adapter portability (swap to curl-client or a mock in tests) without touching call sites. php artisan tinker → app(Http\Client\HttpClient::class) is the fastest way to confirm the binding resolves before writing code.

Implementation Patterns

Constructor injection over facades. This package predates Laravel's Http facade (Laravel 7) by several years, so there is no convenient facade. Standard pattern: type-hint HttpClient (and HttpAsyncClient separately) in constructors, and wrap calls in a small domain service so your controllers never see HTTPlug directly.

Adapter swap via config. The main value of the package is that config/httplug.php picks the adapter. Configure it once per environment, keep application code adapter-agnostic. This lets you, for example, use a synchronous Guzzle adapter in web requests and a React adapter in a long-running command — if the package exposes named clients, use a dedicated binding in a small service provider for the async one; otherwise resolve two providers yourself with Http\Discovery.

Wrap in an application-level client. Define interface MyApi { public function fetch(...): array; } and an implementation that takes HttpClient + MessageFactory. This is the only place that knows about PSR-7 request construction, and it is the seam you swap in tests.

Testing with php-http/mock-client. The highest-leverage pattern. In a test case or a dedicated TestCase, rebind the interface:

$mock = new \Http\Client\Common\PluginClient(
    new \Http\Mock\Client(),
    [/* plugins under test */]
);
$this->app->instance(HttpClient::class, $mock);

Then assert on $mock->getLastRequest() and pre-load responses with $mock->addResponse(...). No network, no Guzzle mocking gymnastics.

Plugins for cross-cutting behaviour. php-http/client-common plugins are how you get retries, redirects, logging, auth headers, and request history. Register them either through the package's config (if it has a plugins array — resolve class names through the container) or by decorating the resolved client in your own provider:

$this->app->extend(HttpClient::class, function (HttpClient $client, $app) {
    return new PluginClient($client, [
        new \Http\Client\Common\Plugin\RetryPlugin(new \Http\Client\Common\Plugin\RetryPlugin(...)),
        new \Http\Client\Common\Plugin\LoggerPlugin($app['log']->channel('http')),
    ]);
});

Queue jobs and commands are a natural fit: inject the client, and because the binding is a singleton you reuse the underlying connection/handler (Guzzle) across many calls in a single job.

Gotchas and Tips

It is effectively abandoned. Last tagged release August 2016, ~12 stars. It targets Laravel 5.x and HTTPlug 1.x; the ecosystem moved to PSR-18 (psr/http-client), and php-http's own httplug is now a compatibility shim. Expect illuminate/support version constraints and PHP <8 constraints to block installation in modern apps. Treat it as a legacy-project tool, not a new-project choice; for new Laravel, use the built-in Http facade or GuzzleHttp\Client.

Forgetting the adapter is the #1 failure. Without one installed, resolution throws a discovery error ("No PSR-18 clients/PSR-7 implementations found") the moment the container tries to build the client — often on an unrelated page because something type-hints it. Install the adapter in require, not require-dev.

Guzzle 5 vs Guzzle 6 message types. The abstraction promises PSR-7, but the Guzzle 5 adapter returns GuzzleHttp\Message\Response. If you type-hint or instanceof against Psr\Http\Message\ResponseInterface, Guzzle 5 will bite you. Pin php-http/guzzle6-adapter and verify your adapter's message compatibility.

Exceptions are not Guzzle's. HTTPlug throws Http\Client\Exception and its subclasses (HttpException, NetworkException, RequestException) — not GuzzleHttp\Exception\RequestException. Existing catch blocks silently stop matching, so 404s and timeouts surface as 500s. Centralise catching in your wrapper service.

Not every adapter is async. HttpAsyncClient is a separate interface. $client instanceof HttpAsyncClient before calling sendAsyncRequest, or bind the async interface explicitly. The synchronous binding won't proxy for you.

Singleton + config cache. php artisan config:cache freezes the adapter choice; runtime config()->set() after the client is resolved changes nothing because it's already constructed. Clear the cache after editing config/httplug.php.

Decorated clients break instanceof. Once you wrap the client in a PluginClient, the concrete adapter class is hidden — don't type-hint GuzzleHttp\Client anywhere, and don't reach for adapter-specific methods like getConfig().

Debugging requests. Attach a HistoryPlugin and dump() the last request/response; alternatively LoggerPlugin with a dedicated log channel. Guzzle's debug => true option is not portable across adapters, so history/logging is the adapter-agnostic path.

Override via $this->app->extend() rather than editing vendor config. If you need a custom client, bind Http\Client\HttpClient in a provider registered after the package's provider (or use extend), so you keep the package's config-driven defaults for everything else.

Watch out in long-running workers. The singleton persists for the worker's lifetime; a stale pooled connection can cause odd timeouts. If the package offers a reset/forgetInstance path, use it between jobs; otherwise rebind periodically. (This predates Octane, so there's no built-in handling.)

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource