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

Psr 18 Guzzle Adapter Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

What the artifact actually is. jord-jd/psr-18-guzzle-adapter is a single-purpose shim: it wraps GuzzleHttp\Client so callers can depend on Psr\Http\Client\ClientInterface instead of Guzzle concretions. The README is two sentences; the release notes are empty (v3.0.0 contains only a changelog link, v2.0.0 is a rename, v1.2.0 adds PHP 8, v1.1.0 adds Guzzle 7). A TPM should evaluate this as procurement of ~100 lines of glue code, not as a platform dependency. The entire decision is therefore about risk containment and exit cost, not about capability.

Architecture fit. PSR-18 is the right seam for a Laravel codebase for three concrete reasons: (1) third-party and future packages increasingly type-hint ClientInterface, so you need a container binding that satisfies them; (2) it lets domain/services code stop importing GuzzleHttp\Client, which is the real source of test friction; (3) it preserves Guzzle's middleware investment where you have it (retries, logging, auth handlers), which is not true of a hard migration to Symfony HttpClient or Buzz.

The fit is weak if the team already standardizes on Laravel's Illuminate\Support\Facades\Http. Laravel's HTTP client is Guzzle-backed but is not itself PSR-18; layering this adapter alongside it creates two HTTP surfaces with divergent retry, timeout, logging, and metrics behaviour. That is an operational regression, not a standardisation win. Adopt this only where a PSR-18 seam is actually required by a consumer, and pick one primary HTTP surface.

Integration feasibility. Mechanically trivial: composer require, then bind the adapter to ClientInterface in a service provider, then inject the interface. The constraint is not install effort but the surrounding wiring: PSR-18 gives you only sendRequest(), so you separately need a PSR-17 factory (guzzlehttp/psr7 or nyholm/psr7) to construct requests, and you need to decide where middleware and configuration live. Note also that the supplied engineering notes reference a Psr18GuzzleAdapterServiceProvider and a getAdapter() method; neither is evidenced in the README. Doc surfaces that disagree are themselves a risk signal — assume manual wiring, no auto-discovery, and verify every class name against the source before committing to a plan.

Technical risk. Ranked:

Risk Assessment
PSR-18 conformance gaps High impact. PSR-18 requires that non-2xx responses be returned, not thrown, and that transport errors be raised as ClientExceptionInterface / NetworkExceptionInterface / RequestExceptionInterface. Guzzle defaults to http_errors: true and throws its own hierarchy that does not satisfy PSR-18. If the adapter does not force http_errors => false and map exceptions, consumers receive errors they are not contracted to catch. Must be verified by test, not by reading the README.
Supply chain / abandonment High likelihood, low blast radius. 9 stars, 0 dependents, single maintainer, no SECURITY.md, no CI or PHP-matrix badges, and one major version bump with zero migration notes — meaning an upgrade can break you with no written signal.
License Requires legal sign-off. LGPL-3.0 is highly atypical in the PHP ecosystem (which is near-universally MIT/BSD). It is almost certainly fine for unmodified Composer use, but it complicates forking and redistribution.
Redundancy / build-vs-buy Real. php-http/guzzle7-adapter (MIT, php-http org, established) solves the same problem, and an in-house adapter is roughly a day of work. There is no evident differentiator justifying a one-maintainer dependency.
Date/data quality The last-release date (2026-07-18) is forward-dated relative to a v1.0.0→v3.0.0 history. Treat metadata as unverified.

Key questions for the spike owner.

  1. Does the adapter pass a written conformance checklist: non-2xx returns response; connection/timeout errors surface as NetworkExceptionInterface; malformed/refused requests as RequestExceptionInterface; request body is rewound on retry/redirect?
  2. Which Guzzle major versions and PHP versions are actually tested in CI?
  3. Is TransferStats, async/promises, or per-request Guzzle options accessible at all — and if not, what is the sanctioned escape hatch?
  4. Where do our retry, timeout, auth, and correlation-ID middlewares live after adoption?
  5. Is there a supported path if the maintainer disappears — i.e. can we fork under our own namespace without LGPL complexity?
  6. Does the consumer set actually need PSR-18, or is "standardisation" aspirational?
  7. Do we accept two HTTP surfaces, or is this adoption conditional on deprecating direct Guzzle?

Integration Approach

Stack fit. Assume Laravel 8+ with Guzzle 7 (and Guzzle 8 unverified). The adapter sits below application code and above Guzzle; it must never be referenced directly by domain code. The correct shape is an internal boundary — bind Psr\Http\Client\ClientInterface once, and treat the concrete adapter class as an implementation detail swappable in one file:

// AppServiceProvider::register()
$this->app->singleton(\Psr\Http\Client\ClientInterface::class, fn () => new GuzzleAdapter(
    new \GuzzleHttp\Client([ /* base_uri, timeout, http_errors => false, handlers */ ])
));
$this->app->singleton(\Psr\Http\Message\RequestFactoryInterface::class, fn () => new \GuzzleHttp\Psr7\HttpFactory());

If the internal notes about a package service provider turn out to be accurate, prefer explicit wiring anyway — auto-discovery that isn't documented is a liability, not a convenience.

Migration path. Do not migrate call sites first. Sequence:

  1. Legal/licence review (LGPL-3.0) and confirmation of redistribution posture — gate.
  2. Conformance spike (2–3 days): build the test matrix from the key questions above against a local fork, including a stubbed transport for error cases. Output is a written pass/fail, not an opinion.
  3. Vendor decision. If the spike passes, still evaluate php-http/guzzle7-adapter and an in-house ~100-line adapter as comparators, scored on licence, maintenance, and conformance. Default recommendation: in-house or php-http, with this package as the reference implementation for behaviour.
  4. Introduce the seam in AppServiceProvider plus an architecture test (e.g. PHPStan/Deptrac rule) banning GuzzleHttp\Client imports outside the provider.
  5. Move new code first, then refactor existing services in batches; keep Guzzle-specific middleware call sites on Guzzle until behaviour is proven equivalent.
  6. Consolidate configuration: one place for base URI, timeouts, retries, headers, and logging.

Compatibility notes to verify, not assume: PHP version floor and ceiling; Guzzle 7 vs 8; PSR-7 implementation used for request construction (must match what the adapter returns, or response body typing surprises appear); Laravel's container resolution of ClientInterface in queued jobs and console commands; and test tooling — mock ClientInterface, never the adapter.

Sequencing gates. Gate 1: licence cleared. Gate 2: conformance checklist green. Gate 3: single HTTP surface agreed in writing. Gate 4: observability parity demonstrated (same log/metric output as current Guzzle path). Only then roll past a single non-critical service.

Operational Impact

Maintenance. Realistic cost is low but non-zero: one Composer constraint to own, one adapter to monitor, one upstream to watch. Because dependents = 0, there is no community signal that a breakage will be caught before we hit it. Budget roughly 1–2 engineer-days to vendor or reimplement this internally, which buys permanent control over licence, exception semantics, and release timing. Given the empty release notes and an undocumented v3 breaking change, pinning to an exact version is mandatory and "upgrade to latest" must never be an unreviewed action.

Support. Two artifacts are needed before rollout: (a) a runbook documenting the exception taxonomy and what each maps to at the application layer, since PSR-18 deliberately hides transport detail and stack traces will still show Guzzle internals; (b) a one-page cheat sheet mapping Guzzle idioms (request('GET', ...), client-level defaults, TransferStats) to their PSR-18 equivalents and stating explicitly what is no longer available. Without these, every debugging session becomes a rediscovery of the abstraction boundary.

Scaling. Per-request overhead is negligible — a thin pass-through call. The scaling concerns are architectural, not computational: bind the client as a singleton so connection pooling is preserved across requests in a worker; confirm that queued jobs and Horizon workers get the same configured instance rather than a fresh default client; and ensure middleware (retry, backoff, rate limiting) is applied centrally, because a PSR-18 seam makes it easy for teams to hand-roll retries at call sites and multiply load during an upstream incident. No statefulness, so horizontal scaling and multi-region deployment are unaffected.

Failure modes.

Failure How it shows up Mitigation
Non-2xx thrown instead of returned Uncaught Guzzle exception in a consumer expecting a response; error-handling branches silently dead Explicit conformance test; force http_errors => false in the client config
Exception type leakage catch (ClientExceptionInterface) never matches; outages look like unhandled 500s Adapter-level mapping + test per PSR-18 exception interface
Middleware drift Retries/logging present on the Guzzle path but absent on the PSR-18 path — or vice versa Centralise middleware; integration test asserting a retry actually happens
Duplicate retries Both Guzzle middleware and application retry logic fire; upstream sees 4–9× traffic Single retry owner, documented
Abandonment No updates; a Guzzle/PHP major forces an unplanned fork Pin version; keep the seam to one file; pre-approve fork/in-house fallback
Licence surprise at audit Distribution or fork restricted late Resolve before adoption, not after

Ramp-up. An experienced Laravel engineer is productive in half a day with the cheat sheet and a working example; the genuine ramp is conceptual, not syntactic — understanding that PSR-18 is a subset and that anything Guzzle-specific now requires a deliberate, reviewed exception to the boundary. Reinforce with an architecture test rather than documentation alone.

TPM recommendation. Do not adopt this package as a direct production dependency on the strength of its own merits. Use it as a reference implementation and one-day spike, then ship an internal MIT-licensed adapter (or php-http/guzzle7-adapter) behind a single ClientInterface binding. The value on offer — a PSR-18 seam over existing Guzzle investment — is real and worth capturing; the specific artifact is small, single-maintainer, atypically licensed, undocumented at the release level, and has zero production dependents. Exit criteria for revisiting: the package gains CI badges with a published PHP/Guzzle matrix, a SECURITY.md, and meaningful release notes — or the upstream maintainer is prepared to transfer/fork under a permissive licence.

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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package