Skip to main content

Public API: cache headers for a CDN

The public read answers of OpenCatalogi can be kept by a CDN or a browser. A visitor without an account then gets a cached answer, and Nextcloud answers fewer requests.

Which answers​

  • GET /api/{catalogSlug}: the publications of a catalogue
  • GET /api/{catalogSlug}/{id}: one publication
  • GET /api/{catalogSlug}/{id}/attachments: its attachments
  • GET /api/search: the public search

What the headers say​

calleranswerheaders
no account200Cache-Control: public, max-age=N, must-revalidate, a weak ETag over the answer, Vary: Origin, Accept, Accept-Language
no account, If-None-Match matches304, no bodythe same ETag and Cache-Control
signed inanyCache-Control: private, no-store, no ETag
anyonean error (4xx, 5xx)no public cache header
no account, the request carries a body, cache time above 0200Cache-Control: no-store, no ETag

A signed-in answer can hold records the public cannot read, so it is never cached. The ETag is computed over the answer after the access check, so it does not reveal that a hidden record changed.

Set the cache time​

Open Administration settings → OpenCatalogi → Publishing options and set Public cache time (seconds). The default is 60, the highest value is 3600 (one hour). Set 0 to switch the public cache headers off; the answers then go out as before.

The same value is the app config key public_api_cache_seconds:

occ config:app:set opencatalogi public_api_cache_seconds --value=300

Setting up a CDN​

  • Let the CDN respect Cache-Control and ETag from the origin. It should revalidate with If-None-Match once max-age has passed.
  • Keep Origin, Accept and Accept-Language in the cache key. The answers carry Vary: Origin, Accept, Accept-Language because the CORS header, the format (a publication answers JSON, or schema.org JSON-LD for Accept: application/ld+json) and the language differ per site and per reader. A CDN that ignores Vary: Origin can hand one site's CORS answer to another site.
  • Do not cache requests that carry a Nextcloud session cookie or an Authorization header. The origin already marks those answers private, no-store.
  • Bypass the cache for those requests as well: do not serve them from it either. A cached anonymous answer for the same URL would otherwise reach a signed-in editor, without concept or future-dated publications.
  • Views served from the CDN are not counted in the publication statistics. Only a request that reaches Nextcloud and gets a full answer counts as a view; a revalidation answered with 304 does not.

The withdrawal delay​

A withdrawn or changed publication can stay visible in a cached answer for up to the cache time. With the default of 60 seconds that is one minute. Choose a shorter time if a withdrawal must disappear sooner, or purge the CDN by URL after a withdrawal. A purge does not reach the browsers of visitors who already received the answer: they keep it until its max-age has passed.