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

Guzzle Factory Laravel Package

graham-campbell/guzzle-factory

A simple Guzzle factory with sensible defaults for PHP 7.4–8.5. Create ready-to-use clients in one call, customize the handler stack, and optionally enable best-effort transport sharing for handler-lifetime reuse.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. Guzzle Factory is a single-class, framework-agnostic construction helper — not an HTTP abstraction layer. GuzzleFactory::make() returns a stock GuzzleHttp\Client, so adopting it introduces no new interface, no new base class, and no vendor lock-in at the call site. For a Laravel codebase where Guzzle clients are constructed ad hoc across controllers, jobs, Artisan commands, and service classes, that is the right shape: it centralizes retry policy, timeout, base URI, and TLS defaults without changing the type application code depends on. It is explicitly not a replacement for Laravel's Http facade or a PSR-18 abstraction, and it should not be positioned as one. Treat it as a configurable client factory behind an internal seam.

Integration feasibility. Composer install, one class, one static entry point. Implementation effort is small — roughly 0.5–1 day for a container binding plus config profiles, and a further 2–5 days to migrate existing call sites depending on how many Guzzle clients are scattered through the codebase. Hard prerequisites are narrow and checkable: Guzzle ≥ 7.11 and PHP 7.4–8.5 (the package's own PHP support window is broader than most Laravel 9–11 deployments, so this is rarely a blocker). The real cost is inventory and governance, not code.

Technical risk. Functionally low, but four items need explicit sign-off before approval:

  • v8 is a breaking release, not a version bump. It removed direct handler-stack creation from the public API and replaced it with a HandlerStack mutator callback plus a TransportSharing argument. Any existing internal wrapper built on the older handler-stack accessor must be rewritten. Confirm whether we are already on that removed API — if so, this is a migration, not an adoption.
  • Defaults are policy, not convenience. Automatic retry on 429 and configurable 4xx retry codes are unsafe for non-idempotent verbs (POST payments, outbound webhooks, order submission). A TLS 1.2 minimum is a security improvement but can break legacy partner endpoints. Both must be reviewed per integration, not accepted as package defaults.
  • Documentation-to-API fidelity. The README demonstrates transport sharing via GuzzleHttp\TransportSharing::HANDLER_PREFER. Verify that constant and namespace exist in the pinned Guzzle 7.11 release and that behavior is genuinely "best effort" before designing around it. Low-severity, but it is the one advanced feature we would otherwise assume works.
  • Supply-chain exposure. Single maintainer, zero listed dependents, but an active release cadence, a changelog and release history back to v1, a published security policy, and a Tidelift commercial support channel. Low probability, medium impact. Mitigated almost entirely by the internal seam and a pinned constraint — which is exactly why the seam is non-negotiable.

Also weigh the market signal: an overall score of 8.7 against an opportunity score of 55.25 says this is a well-executed package with limited strategic differentiation. The functionality is roughly 40 lines of code any team could write. We are buying maintenance and defaults discipline, not capability — and that changes the build-vs-buy threshold only if the seam keeps exit cost near zero.

Key questions to resolve before approval.

  1. How many Guzzle clients exist today, and how many use verify => false, hardcoded timeouts, or bespoke retry logic? This baseline doubles as the business case.
  2. Which integrations are non-idempotent, and do any require retries on 4xx or TLS below 1.2?
  3. Do we already depend on handler-stack internals, i.e., are we on v8's removed API?
  4. Is our Guzzle constraint already ≥ 7.11, and does any transitive package pin it lower?
  5. What per-service profiles do we need — base URI, timeout, retry budget, retryable status codes — and do they live in config/services.php or a dedicated config file?
  6. Is Tidelift coverage warranted for revenue-path consumers, or is the seam sufficient?
  7. What are the pilot's exit criteria, and who owns the internal seam long term?

Integration Approach

Stack fit. Laravel 9–11, PHP 8.1+, Guzzle 7.11+. Bind the factory in a service provider — a singleton plus contextual bindings keyed by upstream service. Drive base URI, timeout, retry count, and retryable status codes from configuration. Because the injected type remains stock GuzzleHttp\Client, it composes cleanly with queues, commands, pipelines, and existing service classes, and it is trivially mockable by swapping a MockHandler-backed client into the container for tests.

The one non-negotiable design decision. Introduce a thin internal HttpClientFactory that calls GuzzleFactory::make() internally, and have application code depend on that seam — never on the vendor static method directly. This costs one small class and buys an exit ramp: if the package is abandoned or a major bump misbehaves, the change is a two-line edit behind the seam rather than a codebase-wide codemod. It is also the single place to enforce retry policy and to attach logging or tracing middleware through the handler-stack callback.

Migration path — strangler, not big-bang.

  1. Audit and baseline. Enumerate every Guzzle client, record its effective configuration, and flag verify => false, hardcoded timeouts, and hardcoded base URIs.
  2. Seam, config, and tests. Implement the internal factory and per-service profiles, then add a snapshot test asserting the effective client configuration per profile. This guards against silent default drift when the package's defaults change across upgrades — the highest-probability long-term failure.
  3. Pilot on two or three non-critical integrations (analytics, logging, notifications). Measure config lines removed, time to add a new endpoint, and defects attributable to the change.
  4. Tiered rollout. Non-critical integrations, then internal service-to-service calls, then revenue-path integrations last, with a short retrospective per tier.
  5. CI ratchet. Add a static check banning new GuzzleHttp\Client( and verify => false outside the seam so usage cannot re-diverge after the migration completes.
  6. Retire bespoke wrappers and duplicated configuration once all tiers are through.

Compatibility and sequencing. Confirm Guzzle 7.11 availability across every dependent service before adopting v8, and verify PHP versions on all deployment targets. Sequence strictly as audit → seam and config → pilot → tiered rollout → CI ratchet. Do not combine the v8 API migration with the first production rollout; land the seam behind the old behavior first, then flip the implementation, so any regression has a single suspect.

Operational Impact

Maintenance. Near zero by design — one class, no transitive dependency beyond Guzzle itself, no configuration surface beyond what we add. The maintenance burden we take on is not in the package but in our profiles and seam, which we own either way. Budget a periodic review of the pinned constraint against upstream releases; the changelog shows a steady cadence with clean semver major bumps, so upgrade planning is predictable. Expect to spend more time on Guzzle's major releases than on this package's.

Support. Community-supported by a single maintainer with a published security policy and a Tidelift commercial channel. This is a realistic bus-factor-of-one scenario, but the blast radius is contained: the seam means we can vendor, fork, or replace the class in hours. Do not assume upstream will absorb our edge cases. For revenue-path consumers, either purchase Tidelift coverage or accept the seam as the sole mitigation — state which, explicitly, in the approval record.

Scaling. No meaningful scaling concern. Client construction is cheap and the singleton binding avoids repeated instantiation. The one scaling-adjacent lever is the opt-in transport sharing mode: enabling it improves connection reuse under high outbound volume, but it is described as best effort and shares handler lifetime, so it deserves a load test before use on high-throughput paths rather than being switched on by default. Retry defaults also interact with load — aggressive retries amplify pressure on a degraded upstream. Set explicit retry budgets per profile rather than inheriting defaults.

Failure modes. Ranked by likelihood and impact:

  • Silent default drift on upgrade — upstream changes a default and every consumer inherits it. Highest likelihood. Mitigated by the per-profile snapshot test.
  • Unsafe retries on non-idempotent requests — duplicate payments or duplicate webhook deliveries. Low likelihood, severe impact. Mitigated by per-profile retry policy and review of every POST consumer before rollout.
  • TLS 1.2 floor breaking a legacy partner — surfaces at first production call. Mitigated by auditing partner endpoints during the pilot tier.
  • Abandonment of a single-maintainer package — low likelihood, contained by the seam.
  • Scope creep into an abstraction layer — the most underrated risk. If engineers start treating the factory as our HTTP abstraction, we rebuild the lock-in we just avoided. The CI ratchet and code review are the controls.

Ramp-up. Essentially none for engineers already familiar with Guzzle; the API is one static call. The learning curve is organizational, not technical: teams must learn to use the seam and the named config profiles instead of constructing clients directly, which is a habit change enforced by linting rather than documentation. Plan a short internal write-up covering the seam, the profile taxonomy, and the retry-policy rules, plus a single worked example per tier. Onboarding a new engineer to "which HTTP client do I use and how is it configured" should take minutes once the profiles are named well — and that naming is the highest-leverage deliverable of the whole effort.

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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
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
cgv/localized-resource