feat(state): cache hydra documentation and entrypoint responses#7929
feat(state): cache hydra documentation and entrypoint responses#7929abderrahimghazali wants to merge 5 commits intoapi-platform:mainfrom
Conversation
24a98c2 to
81420a8
Compare
|
The two CI failures (
For this PR specifically, the 3 files I touched are flagged only for that same Tests for the new processor pass: |
Adds an ETag and revalidating Cache-Control headers to the api_doc and api_entrypoint routes so clients (Admin UI, generated clients, schema parsers) can avoid re-downloading the full documentation when nothing changed. Implemented as a state processor decorating api_platform.state_processor.documentation, mirroring the existing AddLinkHeaderProcessor pattern. The processor computes a strong ETag from the response body and delegates 304 handling to Response::isNotModified(), which respects the client's If-None-Match header. Refs api-platform#4074
81420a8 to
469d86a
Compare
|
I found several issues:
I took the liberty of fixing these in added commits please have a look. |
Summary
Adds HTTP caching headers (ETag + revalidation
Cache-Control) to the API documentation (/docs.{_format}) and entrypoint (/{index}.{_format}) routes so clients can skip re-downloading the body when nothing has changed.Fixes #4074.
Why
These two endpoints are hit on every page load by API Platform Admin and any other client that parses the Hydra documentation. The response is often hundreds of KB (one user reports 280 KB / 1.3 s in #4074) and the content rarely changes between requests. Today there is no cache validator at all, so every fetch re-transfers the full payload.
What changes
ApiPlatform\State\Processor\CacheableDocumentationProcessor, a state processor that decoratesapi_platform.state_processor.documentation(the processor used exclusively byEntrypointActionandDocumentationAction).md5of the response body).Cache-Control: public, max-age=0, must-revalidateso clients always revalidate but can serve from local cache while doing so.Response::isNotModified()which short-circuits to a304 Not Modified(with empty body) when the client sends a matchingIf-None-Match.src/Symfony/Bundle/Resources/config/symfony/events.phpas a decorator at priority300(outermost, so it sees the final serializedResponse). The pattern mirrors the existingAddLinkHeaderProcessor.Responsereturns, non-200 responses, or empty bodies — and because it only decorates thedocumentationprocessor, it cannot affect any non-documentation route.This follows the maintainer's suggestion in #4074 ("we must set etags and basic HTTP cache header on these endpoints").
Why a state processor (not a kernel listener)
API Platform 4.x routes documentation through the same state-processor pipeline as resources (
documentation.serializeat 200,documentation.writeat 100). A processor decorator is the idiomatic extension point — it scopes naturally to the two documentation actions (no route-name sniffing onkernel.response), composes with the stopwatch, and matches the precedent set byAddLinkHeaderProcessor.Tests
New
ApiPlatform\State\Tests\Processor\CacheableDocumentationProcessorTestcovers:public,must-revalidate,max-age=0) are set on a 200 response.If-None-Matchmatching the computed ETag yields a304response with an empty body.Response.requestis present in the context.Test plan
./vendor/bin/phpunit --filter CacheableDocumentationProcessorTest(6/6, 18 assertions)src/Statesuite (60/60, 216 assertions)php -lon all changed files