jacyimp/api-platform-operation-cache
jacyimp/api-platform-operation-cache adds operation-level caching for API Platform in Laravel/PHP applications. Cache expensive or frequently requested operations to reduce latency, lower backend load, and improve API performance and scalability with simple configuration.
Architecture fit. The package occupies the HTTP response-caching layer of a Laravel application: middleware intercepts requests, derives a cache key from URI plus vary dimensions, and serves stored responses. v0.2.0 materially expands that layer from a simple response cache into a small cache-orchestration system — cache groups with URI interpolation, generation-based invalidation, conditional/dynamic invalidation rules, an imperative API, and PSR-14 lifecycle events. Architecturally that is a better fit for content-driven applications (catalog, CMS, marketing sites) where invalidation is driven by domain events rather than TTL, but it also means the package now participates in write paths, not just read paths. Teams should treat it as infrastructure with correctness implications, not a drop-in middleware.
Integration feasibility. Feasible on a standard Laravel stack. It requires no schema changes for the caching itself, but generation-based invalidation requires a durable, shared, atomic counter store — this is the single largest integration constraint. In a single-node deployment with the file cache driver, the package will appear to work and then behave incorrectly under load or across nodes. A Redis (or equivalent) cache store with eviction policy set to noeviction for the counter keyspace should be considered a hard prerequisite, not a recommendation.
Technical risk.
OperationCache metadata syntax" is almost certainly a breaking change to any existing registration code, and the Symfony listener default change alters behavior for anyone who had use_symfony_listeners unset. Budget for churn across the 0.x line.Key questions for the maintainers. Is the generation counter read at store time or lookup time, and what is the documented race behavior under concurrent store + invalidate? What is the recommended eviction/TTL policy for counter keys, and does the package detect counter loss? Is the OperationCache instance syntax backwards compatible with the prior static form, or is a codemod/migration guide provided? What is the supported Laravel/PHP version matrix, and is Octane explicitly tested in CI? Are vary-header defaults fail-closed (over-vary) or fail-open (under-vary)? What is the hit-rate cost of the new global default vary headers on a representative route set?
Stack fit. Best suited to a Laravel 10/11/12 application on PHP 8.2+ with Redis available and a clear separation between "public, cacheable" and "authenticated, uncacheable" routes. Applications already using spatie/laravel-responsecache or hand-rolled middleware should evaluate this as a replacement rather than an addition — running two response caches in one middleware stack produces nondeterministic behavior and doubled Vary handling.
Migration path. Adopt incrementally: (1) pin to an exact 0.2.x patch version and verify the lockfile; (2) start on a single low-risk, high-read-volume route group in staging with lifecycle events wired to logs; (3) migrate one route group at a time, keeping the existing cache middleware active for all others; (4) only after invalidation behavior is validated in staging, move write-path call sites (the imperative API) into application services behind a thin internal facade. Do not expose the imperative invalidation API directly to domain code — wrap it so a future 0.x breaking change is a one-file edit.
Compatibility. Confirm three things before build work begins: Laravel/PHP version support, cache driver support (Redis required for multi-node correctness), and middleware ordering relative to session/auth/session-cookie middleware. Anything served to an authenticated user must be excluded by explicit deny-list, not by omission.
Sequencing. Ship observability before cache. Wire PSR-14 events into metrics (hit rate, miss rate, invalidation count by group) and a stale-content alert before enabling caching for real traffic. Then enable in staging → canary a single node or small traffic slice → full rollout per route group. The app-wide default vary headers should be configured and reviewed by whoever owns security, not defaulted implicitly.
Maintenance. Expect active 0.x churn; plan for a dependency upgrade every one to two releases and reserve capacity for a breaking-change migration before 1.0. Pin versions, read every changelog, and keep the integration surface small (middleware registration, group definitions, invalidation facade).
Support. This is a pre-1.0 package; assume limited commercial support and rely on maintainer responsiveness plus source readability. Given the correctness stakes of generation-based invalidation, at least one engineer should be able to read the invalidation code path — not just configure it.
Scaling. Read scaling is the easy part — cache hits are cheap. The scaling risk is invalidation fan-out and counter contention: high-frequency invalidation of a global (*) group serializes on a single counter and can become a hot key. Model expected invalidation rate per group before launch, and avoid global invalidation in request paths (do it asynchronously). Prefix invalidation via product:* is cheap by design, which is the main argument for the generation model.
Failure modes to instrument. (1) Counter loss/eviction → silent stale content; alert on counter key absence and on cache-hit age exceeding the expected invalidation window. (2) Cardinality explosion from interpolated groups → watch cache key count and memory. (3) Cross-user leakage from missing vary dimensions → assert on Vary and Cache-Control headers in integration tests, and test with a logged-in session token. (4) Listener exceptions on the hot path → wrap listeners defensively, never let telemetry break a response. (5) Stampede on cold start or after a flush → confirm locking or serve-stale behavior. (6) Octane state bleed → run a soak test with concurrent differing requests.
Ramp-up. Low for configuration, moderate for correct invalidation design. Budget roughly one engineer-week for a first route group including observability, plus a security review of vary headers and cacheability deny-lists. The concepts that require actual learning are the generation model's semantics (what "exact" vs "prefix" vs "global" invalidation actually guarantees and what it leaves stale) and the interaction between conditional/dynamic invalidation rules and the domain event model. Document an invalidation runbook for on-call — who can invalidate what, via which mechanism, and how to confirm it took effect — before this reaches production.
How can I help you explore Laravel packages today?