micheh/psr7-cache
PSR-7 HTTP caching middleware for PHP that stores and reuses responses according to RFC 7234, handles cache headers and conditional requests, and integrates with PSR-7/PSR-15 stacks to reduce backend load.
If-Match / If-Unmodified-Since support via $util->hasStateValidator($request) and $util->hasCurrentState($request, $eTag, $lastModified). This turns the package from a read-side caching helper into a way to prevent lost updates (two editors or two clients overwriting each other) without inventing a bespoke version column, advisory locks, or hand-rolled precondition parsing in every controller. That's a feature decision you can make now and a roadmap decision you can defer: you no longer need to budget a sprint for concurrency control on PATCH/PUT endpoints.* handling, precedence between If-Match and If-Unmodified-Since, correct 412 Precondition Failed vs 304 Not Modified responses, and entity-tag comparison rules. Adopting a small, focused package is cheaper and lower-risk than owning that logic in-house.If-None-Match / 304 handling on GETs reduces egress and origin work for mobile clients, public APIs, and CDN-fronted responses. This is a directly measurable line item, useful when justifying work that otherwise looks like plumbing.If-None-Match is a subtle but meaningful addition: it aligns behavior with proxies and compression layers that legitimately weaken tags, reducing "stale content served" and "cache never hits" bug classes that are painful to reproduce and often misattributed to the CDN.If-None-Match) and unsafe-method preconditions (If-Match) are independent rollouts. Caching can ship behind existing endpoints with near-zero client coordination; precondition enforcement is a contract change for API consumers and should be versioned, documented, and paired with a 412 error-handling story for clients.Adopt when:
Last-Modified value between requests.304/412 semantics handled consistently rather than reimplemented per controller, and you value a small dependency surface over a full HTTP-caching framework.Look elsewhere when:
If-Match becomes a breaking change and you'll need a transition or opt-in strategy first.Risk to flag: the 0.x version number signals no stability promise. The surface is small, but wrapping the two utility calls behind your own abstraction costs little and buys you insulation from renames and signature changes in 1.0.
For executives (one paragraph): This is a small, low-cost library that makes our API behave the way HTTP is supposed to behave. Two concrete payoffs: (1) clients that already have the latest copy of a resource get a cheap "nothing changed" response instead of a full payload, cutting bandwidth and server load; (2) when two people or two automated clients try to modify the same record, the second write is rejected instead of silently clobbering the first. The second capability is new in this release and removes a class of data-loss bugs we would otherwise have to engineer around ourselves. Cost is a single dependency and modest integration work; risk is contained because the package is small, the behavior is standardized, and we can wrap it so a future version bump doesn't ripple through our code.
For engineering (one paragraph): Version 0.5 adds unsafe conditional request support — If-Match and If-Unmodified-Since — exposed as $util->hasStateValidator($request) (does this request carry a precondition?) and $util->hasCurrentState($request, $eTag, $lastModified) (is that precondition satisfied?). Together these give us optimistic concurrency control on writes: validate, return 412 Precondition Failed on mismatch, and clients get a standard, well-understood retry contract rather than a custom conflict payload. It also adds weak ETag comparison for If-None-Match, which fixes incorrect cache misses when intermediaries or compression weaken tags. Recommended integration: wrap both calls in a single internal trait or middleware so the package's pre-1.0 API churn is absorbed in one place, emit ETags on read endpoints first (low risk, immediate measurable benefit), then layer precondition enforcement onto mutating endpoints as a documented, versioned API contract change with client-side 412 handling shipped before enforcement is mandatory.
How can I help you explore Laravel packages today?