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

Http Client Laravel Package

symfony/http-client

Symfony HttpClient provides powerful methods to fetch HTTP resources synchronously or asynchronously, with a clean API for building requests, handling responses, streaming, and testing HTTP calls in PHP applications.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit This is a framework-agnostic Symfony Component, not a Laravel package. It ships no service provider, no config file, and no facade — so "fit" is a decision about whether to introduce a second outbound HTTP stack next to the one Laravel already wraps (Guzzle). It is a strong fit, but only under specific conditions:

  • Port-style adoption — program against Symfony\Contracts\HttpClient\HttpClientInterface in your domain services and bind it in a provider. This gives you MockHttpClient for tests, decorators for logging/metrics/tracing, and a clean seam to swap implementations later. This is the highest-value, lowest-risk pattern.
  • PSR-18 interoperability — Psr18Client/HttplugClient let you satisfy third-party SDKs that type-hint Psr\Http\Client\ClientInterface (Stripe, AWS, most AI SDKs) without rewriting call sites. You get the swap without the migration.
  • Capabilities Guzzle makes awkward — true async fan-out via curl_multi (AsyncResponse, stream()), NoPrivateNetworkHttpClient as a first-class SSRF guard for user-supplied URLs (webhooks, URL previews, image imports), ScopingHttpClient for per-host base URI/timeout policy, RetryableHttpClient with backoff, and streaming with progress callbacks.
  • Where it fits poorly — teams that want Http::withToken(...)->post(...) ergonomics. This component is lower-level; you will be writing and maintaining a thin wrapper, and that wrapper is your real product surface.

Data-quality flags for diligence: Dependents: 0 and 2,029 stars are artifacts of this being a read-only split of symfony/symfony. Real adoption is not represented here. Do not treat these as adoption signals in either direction, and do not treat the star count as a maturity proxy.

Integration feasibility High, with caveats.

  • composer require symfony/http-client plus symfony/http-client-contracts; PSR-18 use additionally needs psr/http-client and a PSR-7 implementation (nyholm/psr7 is the light choice).
  • Transport selection matters operationally: CurlHttpClient requires ext-curl and is the production default (proxy, HTTP/2/3, connection reuse); NativeHttpClient requires allow_url_fopen and has a materially weaker edge-case record in the changelogs (dechunk filter replacement, proxy handling, truncated streams). Pick curl and pin it.
  • PHP floor is the gating constraint. Symfony 8.x targets the newest PHP (verify the exact floor for 8.1 before committing); 7.4 and 6.4 LTS cover older fleets. Confirm against your Laravel version's PHP floor before you pick a major line.
  • Coexistence with Guzzle is technically clean but organizationally expensive: two retry policies, two timeout semantics, two error hierarchies. Budget for eventual consolidation or accept permanent duplication explicitly.

Technical risk

  • Security-relevant CVE in the component's own SSRF guard. CVE-2026-48736 (IPv6 transition forms bypassing NoPrivateNetworkHttpClient) is patched across 5.4, 6.4, 7.4 and 8.1. If SSRF protection is your reason for adopting this component, an unpatched pin gives you false assurance — worse than no guard, because teams stop reviewing URLs. Pin to patched versions and assert it in CI.
  • Behavior instability on a security path. Cross-authority redirect header stripping shipped in #65019 and was reverted in #65036 within the same patch window. Redirect/auth-header semantics changed twice in patch releases. Pin patch versions in production lockfiles; do not float ^7.4.
  • Immature caching layer. CachingHttpClient was reworked for RFC 9111 in 7.4 and has accumulated follow-on fixes (trusted hosts, header replacement, ordering after UriTemplate/Scoping). Treat as beta-grade; do not put it in a hot path without a fallback.
  • Async is the sharpest edge. Recent fixes target AsyncResponse::stream() consumption guards, __destruct() throwing, abandoned-wrapper behavior, and first-chunk re-yielding after reconnect. Concurrency bugs here surface as hangs, leaked sockets, or silent short reads — not clean exceptions.
  • Changelog reversals in payload handling. "Don't reject highly compressed responses" (8.1.8) reverses prior decompression-bomb protection. If you relied on the client to bound decompressed size, that guarantee moved — enforce max_duration/body limits at the application layer.
  • Issue routing. Bugs and PRs live in symfony/symfony, not this repo. Your security scanner, issue-link tooling, and changelog automation will point at the wrong place.
  • Maintainer concentration. Fix authorship is heavily concentrated in one maintainer. Mitigated by MIT license, breadth of Symfony commercial backing, and the fact that a full retreat to Guzzle/curl is mechanically possible behind your interface.

Key questions

  1. What is the fleet PHP floor, and therefore which major line (6.4 LTS vs 7.4 vs 8.1) are we standardizing on?
  2. Are we adopting this as a replacement for Guzzle, a PSR-18 adapter for third-party SDKs, or a supplement for async/SSRF cases? Each has a very different cost.
  3. Who owns outbound HTTP policy — timeouts, retries with jitter, per-host concurrency caps, redirect limits, SSRF allowlists — and does it live in one decorator stack or per-call?
  4. Do we actually need the async/concurrency win, or is the real driver SSRF plus testability? If the latter, an adapter-only scope is defensible and much cheaper.
  5. Do we need the RFC 9111 caching client, or is Redis/CDN sufficient? (Recommend: skip until it has a stable patch history.)
  6. Test strategy: do we standardize on MockHttpClient for new code and leave Guzzle MockHandler in place for legacy, or converge?
  7. Is there appetite to migrate existing Guzzle call sites, or is a permanent dual stack acceptable? Get this in writing — dual stacks decay.

Integration Approach

Stack fit Framework-agnostic component; Laravel integration is entirely yours to build. Recommended shape: an OutboundHttp port interface in your domain layer, a Laravel service provider binding HttpClientInterface to a decorated CurlHttpClient, and a single factory for scoped clients. Do not attempt to rewire Laravel's Http facade — it is Guzzle-shaped and you will fight it. Add Psr18Client alongside so third-party SDKs can be pointed at the same transport and inherit the same timeout/retry/observability policy.

Migration path Sequence to maximize value per unit of risk:

  1. Spike (1 week). Bind the client, prove curl transport, mock-based tests, and log/trace decoration. Validate PHP-floor compatibility against actual Laravel version.
  2. Security pin + policy layer. Patched version pinned; NoPrivateNetworkHttpClient wrap for any user-supplied URL path; timeouts, max_redirects, per-host concurrency caps, and jittered retry in one decorator.
  3. PSR-18 swap for SDKs. Replace Guzzle as the PSR-18 implementation behind Stripe/AWS/AI SDK clients. Zero call-site churn, immediate policy inheritance. Best ROI.
  4. New code uses the port. All new outbound integrations land on HttpClientInterface with MockHttpClient tests.
  5. Selective legacy migration. Only where there is a measurable win: parallel fan-out, streaming downloads, SSRF-sensitive endpoints. Do not migrate for consistency's sake alone.
  6. Caching client last, or never.

Compatibility Pin the Symfony minor line to your PHP floor; keep psr/http-client and a single PSR-7 implementation; require ext-curl in composer.json and fail fast if absent. If you run Laravel Octane or long-lived workers, explicitly review CurlHttpClient instance reuse and reset() semantics across requests — sharing client state between requests is a documented regression area in the 6.4/7.3 patch lines.

Sequencing Security pin → observability decorator → policy (timeouts/retries/caps) → PSR-18 swap → async adoption → caching. Adopting async before observability is the common failure: you get concurrent requests and no way to see which one hung.

Operational Impact

Maintenance High patch cadence across four maintained branches (5.4, 6.4, 7.4, 8.1). Automate dependency PRs, but gate merges on a changelog read — regressions and reversals are visible in release notes and invisible in semver. Pin exact patch versions in production lockfiles; float only in staging. Track the monorepo release feed, not this repo's. MIT with no vendor SLA: you own the failure.

Support Documentation is good (symfony.com component docs are more complete than the repo README, which is a stub pointing outward). Community support via Symfony channels is deep but not contractual. The realistic support model is: your platform team owns the wrapper, the policy layer, and the upgrade cadence; upstream owns the transport internals. Plan for at least one engineer who can read the component source — debugging async and stream behavior from docs alone is not realistic.

Scaling curl_multi delivers real wins on fan-out: N parallel upstream calls at p99 of the slowest rather than the sum. Two scaling hazards: per-host connection caps (regressed twice in patch history — verify max_host_connections behavior after every bump) and long-lived worker state under Octane, where connection reuse and abandoned AsyncResponse objects become memory and socket-leak surfaces. Enforce per-host concurrency ceilings at the decorator level so one vendor's degradation cannot exhaust your FPM pool.

Failure modes

  • Uncaught TransportExceptionInterface → 500s; map to domain errors at the port boundary, always.
  • Timeout semantics differ from Guzzle; default timeouts that were "fine" will surface as new production timeouts. Set them explicitly per scoped client.
  • Redirect handling: bound max_redirects; cross-authority auth-header behavior has changed twice, so never rely on implicit stripping for secret-bearing requests — scope credentials per host.
  • Decompression-bomb protection moved; enforce response size limits yourself.
  • Unpatched NoPrivateNetworkHttpClient gives silent SSRF exposure; assert patched version in CI.
  • Retry amplification when your client retries and Laravel queue retries and the vendor has no idempotency. Add jitter, cap attempts, and require idempotency keys for writes.
  • Abandoned/partially-consumed async responses produce guard errors and destructor noise; always consume or explicitly cancel.
  • Native transport + proxy + chunked responses is the least-tested combination in the changelogs; do not ship it.

Ramp-up A competent PHP engineer is productive in 1–2 days for synchronous use; async, streaming, and decorator composition take roughly a sprint to get right. The real organizational cost is idiom divergence: Laravel developers will reach for Http:: by reflex, so the port must be the path of least resistance (helper function, facade alias, or documented example in the repo). Budget one sprint for standards, the shared wrapper, decorator stack, and test doubles — and treat the "will we fully migrate off Guzzle?" question as a decision to make now, not later. A permanently unconsolidated dual stack is the most likely negative outcome of this adoption, and it is entirely a policy choice rather than a technical constraint.

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