guzzlehttp/cache-subscriber
A Guzzle subscriber that adds caching to HTTP requests, letting you store and reuse responses to reduce redundant network calls. Now deprecated in favor of Guzzle's built-in cache middleware, it remains useful for older projects needing simple response caching.
Recommendation: Do not adopt. This package is archived, deprecated, and architecturally incompatible with the Guzzle version shipped in every supported Laravel release. The pattern it implements is worth reusing; the artifact is not.
Architecture fit
guzzlehttp/cache-subscriber is an implementation of RFC 7234 caching as a Guzzle 5 event subscriber — it attaches to $client->getEmitter() and intercepts before/complete/error events to store and replay responses behind a pluggable storage backend. Guzzle 6 removed the event emitter entirely in favor of the middleware/HandlerStack model. Laravel's HTTP layer (Illuminate\Http\Client, which every Http:: call and most first-party integrations use) sits on Guzzle 7. There is no compatibility shim: the package's core abstraction (GuzzleHttp\Event\SubscriberInterface) no longer exists in the dependency graph we would install. This is not a version-pin problem to be solved with a composer.json constraint; it is a dead extension point.
Integration feasibility
Low, bordering on nil without forking. To use it we would have to pin guzzlehttp/guzzle to ~5.0 in a Laravel app, which is transitively impossible — laravel/framework requires Guzzle 7, and Guzzle 5 does not support PHP 8. A fork would amount to rewriting the package as a Guzzle 7 middleware, at which point we are not adopting this dependency at all.
Technical risk
Vary, Cache-Control: private, and Authorization handling are exactly right. This package predates widespread hardening around that.$str{0} offset syntax, removed each(), implicit nullable params). Even a proof-of-concept would be fighting the runtime.Key questions
kevinrob/guzzle-cache-middleware (the maintained Guzzle 6/7 middleware successor to this package) acceptable as a drop-in concept, or does the team prefer a thin in-house middleware over Laravel's Cache contract?Stack fit
The concept fits Laravel well; the package does not. Laravel already provides the two pieces we need: a PSR-11-compatible cache store (Cache::store() — Redis, Memcached, database, file) and Guzzle middleware injection via Http::withMiddleware() or a shared HandlerStack bound in a service provider. A caching middleware is roughly 150–250 lines against those primitives, and we control the storage semantics.
Migration path
composer.lock across repos for guzzlehttp/guzzle 5.* and for any direct reference to cache-subscriber. Expect zero. Document the finding — this is a cheap gate that closes the ticket.kevinrob/guzzle-cache-middleware as the maintained successor. It is Guzzle 6/7 native, supports PSR-16 storage, and is the de facto migration target for this package's users. Run it behind a spike before committing.CacheMiddleware registered in AppServiceProvider, keyed on method + URI + relevant Vary headers, storing {status, headers, body, stored_at, ttl} in the Laravel cache store. Explicit, testable, ~1 day of work, no abandoned dependency.Compatibility Requires Guzzle 7 and PHP 8.1+ (matching the Laravel version in use). The successor middleware is compatible; this package is not. Storage choice must align with the existing cache infrastructure — Redis if already provisioned, otherwise file store for single-node only.
Sequencing
Cache-Control, ETag revalidation, and Authorization bypass.Maintenance Adopting this package means owning it permanently and immediately — there is no upstream to defer to. That is a standing tax on a team that gets no feature velocity in return. The in-house or successor-middleware routes both leave us with code we can read, patch, and test on our own release cadence.
Support None. No maintainer, no issue triage, no security advisories. Any incident debugs from source, on a codebase written for a PHP version we do not run. Compare against a maintained middleware with an active issue tracker, or against our own code with an on-call owner.
Scaling Caching is the scaling lever here, so the mechanism must be sound. File-based storage breaks under multi-node deployment (no shared invalidation, per-node cache divergence). Redis/Memcached storage introduces its own failure mode: a cache outage should degrade to pass-through, not to 5xx. The middleware must be written to fail open, with a circuit breaker or short connect timeout on the store. Also size the store: cached HTTP bodies are unbounded by default and can quietly become the largest keyspace in Redis — enforce a max body size and a hard TTL ceiling.
Failure modes
| Mode | Symptom | Mitigation |
|---|---|---|
| Stale data served | Callers see outdated records, no error | Short TTLs, ETag/Last-Modified revalidation, explicit invalidation hooks |
| Cross-user leakage | User A receives User B's response | Bypass cache on Authorization/Cookie; never share a store keyed without identity |
Vary mishandling |
Wrong representation (locale, encoding, API version) | Key on all Vary fields; fail closed to no-cache when Vary: * |
| Cache store outage | Latency spike or 5xx | Fail-open pass-through, timeouts, health check |
| Unbounded growth | Redis eviction of unrelated keys | Max body size, TTL cap, namespaced prefix |
| Silent regression | No errors, gradual data drift | Hit-rate/staleness dashboards, sampled cache-vs-origin diffing |
Ramp-up
Near zero for the pattern, which is well understood. The cost is entirely in the review surface: a new engineer must be able to answer "why did this response come back stale?" without reading a deprecated event-emitter implementation. That argues strongly for code the team wrote, with logging on every cache decision (hit/miss/bypass/revalidate) and a debug header in non-production.
Bottom line: the capability is worth having; this package is not a viable vehicle for it. Close the evaluation as rejected-deprecated, reuse the requirement, and spend the one to three days on the maintained successor or an in-house middleware.
How can I help you explore Laravel packages today?