jord-jd/psr-18-guzzle-adapter
A simple PSR-18 adapter for Guzzle, supporting PHP 7.1+ with Guzzle 6 or 7. It keeps Guzzle 6 projects compatible with PSR-18 clients and normalizes Guzzle exceptions to the PSR-18 exception interfaces.
Psr\Http\Client\ClientInterface around GuzzleHttp\Client). It is the enabler for a strategic decision: making HTTP transport an interface in your codebase rather than a concrete Guzzle dependency. Treat the package as an implementation detail of that decision, and weigh the two separately.GuzzleHttp\Client is a future migration cost. Type-hinting ClientInterface preserves the option to swap in Symfony HttpClient, php-http/guzzle7-adapter, or a native client later without rewriting business logic — valuable if you have API-heavy services (integrations, webhooks, partner APIs) on the roadmap.Http::fake() for the Laravel-native client and PSR-18-level fakes for legacy Guzzle paths.ClientInterface in the container, (2) migrate new code and new API clients to PSR-18, (3) migrate existing service classes opportunistically, (4) decide on middleware/retry/async gaps. This is a low-risk background track that rarely needs dedicated sprint capacity.TransferStats, retry/backoff middleware, on_stats hooks — is not exposed through PSR-18. This surfaces an honest inventory question: which of your services genuinely depend on Guzzle semantics versus merely using Guzzle's API?Consider it when:
ClientInterface (or you want them to).Look elsewhere or build in-house when:
Http facade is already PSR-18-compatible and better integrated (fakes, retries, logging, events). Adding a Guzzle adapter to a greenfield project is net new surface area for no gain.TransferStats-based observability will force you back to GuzzleHttp\Client or a bespoke wrapper anyway.v2.0.0 that is only a rename) is a weak signal for anything load-bearing. Budget for a fork.Not a fit at all: high-throughput services where you would benchmark client overhead, or teams without PSR-18 familiarity and no plan to build it.
Executives (30 seconds): "We have a small architectural choice in front of us with outsized long-term value: make our HTTP layer depend on a standard interface instead of one vendor library. It costs a few days of incremental refactoring across existing code and zero runtime overhead. The payoff is that when we need to change HTTP clients — for a migration, a vendor constraint, or a performance reason — it's a config change, not a rewrite across every integration. The package under discussion is a 20-line wrapper; the decision that matters is the standard, not the dependency. Recommendation: adopt the standard, and implement the adapter in-house under MIT rather than taking a dependency on a 9-star, single-maintainer, LGPL-licensed wrapper."
Engineering: "Adopt Psr\Http\Client\ClientInterface as the type-hint for all HTTP dependencies and bind a Guzzle-backed adapter in AppServiceProvider. Two constraints to accept up front: PSR-18 exposes a subset of Guzzle (no async promises, no TransferStats, no middleware stack), and GuzzleException needs normalizing to ClientExceptionInterface at the boundary. Both are tractable; neither disappears by adopting the third-party package. Given the package's size and support profile, the low-risk path is to vendor a small internal adapter with its own tests — same architectural benefit, no license review, no bus-factor exposure."
Architects: "This is a sequencing decision, not a feature. Bind the interface first, migrate new code as it's written, and refactor existing clients opportunistically — never as a big-bang. Gate the refactor on one honest inventory: which services truly need Guzzle-specific capabilities (async, retry middleware, transfer stats) versus merely use Guzzle. Anything in the first bucket stays on the concrete client behind a narrow, documented exception. The interface becomes the default; the concrete client becomes a deliberate, visible escape hatch."
How can I help you explore Laravel packages today?