Skip to main content
Version: 2.27.1

Configure HTTP Caching for Platformatic App

Platformatic Runtime supports HTTP requests caching out of the box. This feature is useful to reduce the number of requests to the same resource and improve the performance of your application.

Enable HTTP Caching

Let's create a simple Platformatic app to demonstrate how to enable HTTP caching.

npx create-platformatic@latest

Here are the answers to the questions to create a Platformatic app with one Platformatic Composer service named main and one Platformatic Service service named internal.

? Where would you like to create your project? .
? Which kind of project do you want to create? @platformatic/composer
? What is the name of the service? main
? Do you want to create another service? yes
? Which kind of project do you want to create? @platformatic/service
? What is the name of the service? internal
? Do you want to create another service? no
? Which service should be exposed? main
? Do you want to use TypeScript? no
? What port do you want to use? 3042
? Do you want to init the git repository? no

To enable HTTP caching, let's set the httpCache property to true in the root platformatic.json file.

{
"$schema": "https://schemas.platformatic.dev/@platformatic/runtime/2.19.0.json",
"entrypoint": "main",
"watch": true,
"autoload": {
"path": "services",
"exclude": [
"docs"
]
},
"logger": {
"level": "{PLT_SERVER_LOGGER_LEVEL}"
},
"server": {
"hostname": "{PLT_SERVER_HOSTNAME}",
"port": "{PORT}"
},
"managementApi": "{PLT_MANAGEMENT_API}",
"httpCache": true
}

Now when the httpCache is enabled, let's add a cache control header to the response of the API. You can do this by adding a cacheControl property to the response object.

Let's add a cached route to the ./services/internal/routes/root.js file.

/// <reference path="../global.d.ts" />
'use strict'
/** @param {import('fastify').FastifyInstance} fastify */
module.exports = async function (fastify, opts) {
fastify.get('/example', async (request, reply) => {
return { hello: fastify.example }
})

let counter = 0
fastify.get('/cached-counter', async (request, reply) => {
reply.header('Cache-Control', 'public, max-age=10')
return { counter: counter++ }
})
}

Now, let's start the Platformatic app.

npm run start

Let's test the /cached-counter route using curl.

curl http://localhost:3042/internal/cached-counter
{"counter":0}
curl http://localhost:3042/internal/cached-counter
{"counter":0}

...and after 10 seconds...

curl http://localhost:3042/internal/cached-counter
{"counter":1}

Http Cache invalidation

By default the cache is invalidated when the max-age is reached. However, you can invalidate the cache manually by calling the globalThis.platformatic.invalidateHttpCache method.

Let's add another route to the ./services/internal/routes/root.js file that invalidates the cache for the /cached-counter route. And also increase the max-age to 180 seconds to be sure that the cache is invalidated and not just expired.

/// <reference path="../global.d.ts" />
'use strict'
/** @param {import('fastify').FastifyInstance} fastify */
module.exports = async function (fastify, opts) {
fastify.get('/example', async (request, reply) => {
return { hello: fastify.example }
})

let counter = 0
fastify.get('/cached-counter', async (request, reply) => {
reply.header('Cache-Control', 'public, max-age=180')
return { counter: counter++ }
})

fastify.delete('/invalidate-cached-counter', async () => {
await globalThis.platformatic.invalidateHttpCache({
keys: [
{
origin: 'http://internal.plt.local',
path: '/cached-counter',
method: 'GET'
}
]
})
})
}

Let's start the Platformatic app.

npm run start

Let's test the /cached-counter route using curl.

curl http://localhost:3042/internal/cached-counter
{"counter":0}

Now, let's invalidate the cache for the /cached-counter route.

curl -X DELETE http://localhost:3042/internal/invalidate-cached-counter

And test the /cached-counter route again.

curl http://localhost:3042/internal/cached-counter
{"counter":1}

Invalidating cache by cache tags

Platformatic Runtime supports cache tags to invalidate related cache entries. Cache tags should be set in one of the response headers. Cache tags should be globally unique.

Let's set the X-Cache-Tags header in the root platformatic.json file.

{
"$schema": "https://schemas.platformatic.dev/@platformatic/runtime/2.19.0.json",
"entrypoint": "main",
"watch": true,
"autoload": {
"path": "services",
"exclude": [
"docs"
]
},
"logger": {
"level": "{PLT_SERVER_LOGGER_LEVEL}"
},
"server": {
"hostname": "{PLT_SERVER_HOSTNAME}",
"port": "{PORT}"
},
"managementApi": "{PLT_MANAGEMENT_API}",
"httpCache": {
"cacheTagsHeader": "X-Cache-Tags"
}
}

Now, let's add a cache tag to the response of the API. And also modify the /invalidate-cached-counter route to invalidate the cache by the cache tag.

/// <reference path="../global.d.ts" />
'use strict'
/** @param {import('fastify').FastifyInstance} fastify */
module.exports = async function (fastify, opts) {
fastify.get('/example', async (request, reply) => {
return { hello: fastify.example }
})

let counter = 0
fastify.get('/cached-counter', async (request, reply) => {
reply.header('Cache-Control', 'public, s-maxage=180')
reply.header('X-Cache-Tags', 'cached-counter-tag')
return { counter: counter++ }
})

fastify.post('/invalidate-cached-counter', async () => {
await globalThis.platformatic.invalidateHttpCache({
tags: ['cached-counter-tag']
})
})
}

Let's start the Platformatic app.

npm run start

Let's test the /cached-counter route using curl.

curl http://localhost:3042/internal/cached-counter
{"counter":0}
curl http://localhost:3042/internal/cached-counter
{"counter":0}

Now, let's invalidate the cache for the /cached-counter route by the cache tag.

curl -X POST http://localhost:3042/internal/invalidate-cached-counter

And test the /cached-counter route again.

curl http://localhost:3042/internal/cached-counter
{"counter":1}