### Complete Fastify Caching and ETag Example Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/usage-examples.md A comprehensive example demonstrating the integration of fastify-caching with ETag generation for content validation and server-side caching for computed data. This setup optimizes performance by reducing redundant computations and network transfers. ```javascript const fastify = require('fastify')() const fastifyCaching = require('@fastify/caching') fastify.register(fastifyCaching, { privacy: fastifyCaching.privacy.PUBLIC, expiresIn: 3600, serverExpiresIn: 86400, cacheSegment: 'app' }) // Computed ETag based on data fastify.get('/api/articles/:id', (req, reply) => { const article = { id: req.params.id, title: 'Article Title', content: 'Article content...', updated: new Date() } const hash = require('crypto') .createHash('md5') .update(JSON.stringify(article)) .digest('hex') // Set ETag and cache TTL reply .etag(hash, 1800000) // 30 minutes .send(article) }) // Server-side cache example fastify.get('/api/summary', (req, reply) => { fastify.cache.get('summary', (err, cached) => { if (err) { console.error('Cache error:', err) return reply.status(500).send(err) } if (cached) { return reply .etag('summary-cached', 300000) .send(cached.item) } const summary = computeExpensiveSummary() fastify.cache.set('summary', summary, 3600000, (err) => { if (err) { console.error('Cache set error:', err) return reply.status(500).send(err) } reply .etag('summary-fresh', 300000) .send(summary) }) }) }) fastify.listen({ port: 3000 }) ``` -------------------------------- ### Install @fastify/caching Source: https://github.com/fastify/fastify-caching/blob/main/README.md Use npm to install the @fastify/caching package. This is the primary step to integrate caching capabilities into your Fastify application. ```bash npm i @fastify/caching ``` -------------------------------- ### Plugin Registration Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/quick-reference.md Examples of how to register the fastify-caching plugin with and without options, including callback style. ```APIDOC ## Plugin Registration ```javascript // Basic await fastify.register(fastifyCaching) // With options await fastify.register(fastifyCaching, { privacy: 'public', expiresIn: 3600, serverExpiresIn: 86400, cache: customCacheInstance, cacheSegment: 'my-cache' }) // Callback style fastify.register(fastifyCaching, options, (err) => { if (err) throw err }) ``` ``` -------------------------------- ### Cache-Control Header Examples Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/protocol-and-compatibility.md Examples of Cache-Control headers generated based on plugin configuration. These headers dictate caching behavior for clients and shared caches. ```text Cache-Control: public ``` ```text Cache-Control: private, max-age=300 ``` ```text Cache-Control: public, max-age=300, s-maxage=86400 ``` ```text Cache-Control: no-cache ``` ```text Cache-Control: no-store ``` -------------------------------- ### Abstract-Cache Protocol: Result Handling Example Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/protocol-and-compatibility.md Provides a practical example of how to handle the CacheResult object returned by cache.get, including error checking and accessing the cached item, storage time, and TTL. ```javascript cache.get('key', (err, result) => { if (err) console.error(err) if (result) { console.log(result.item) // The cached value console.log(result.stored) // When it was stored console.log(result.ttl) // How long until expiry } else { console.log('Not found or expired') } }) ``` -------------------------------- ### Register Fastify Caching Plugin with Options Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/types.md Example of registering the `fastifyCaching` plugin with custom configuration options. Ensure `customCacheInstance` is a valid cache object. ```javascript const fastify = require('fastify')() const fastifyCaching = require('@fastify/caching') await fastify.register(fastifyCaching, { privacy: 'public', expiresIn: 3600, serverExpiresIn: 86400, cacheSegment: 'api-cache', cache: customCacheInstance }) ``` -------------------------------- ### Initial Request for Conditional GET Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/protocol-and-compatibility.md This is the initial request for a resource. The server responds with a 200 OK status and an ETag, which the client caches. ```http GET /resource HTTP/1.1 Host: example.com ``` ```http HTTP/1.1 200 OK ETag: "tag-abc123" Content-Length: 42 {"id": 1, "name": "Resource"} ``` -------------------------------- ### Cache with Segments in Fastify Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/usage-examples.md Shows how to configure and use cache segments for organizing cached data. Includes examples for setting and getting data within a specific segment. ```javascript fastify.register(fastifyCaching, { cacheSegment: 'api-v1' }) fastify.get('/users', (req, reply) => { fastify.cache.set( { id: 'all-users', segment: 'api-v1' }, [{ id: 1, name: 'User 1' }], 3600000, (err) => { if (err) return reply.send(err) reply.send({ cached: true }) } ) }) fastify.get('/users/:id', (req, reply) => { fastify.cache.get( { id: `user:${req.params.id}`, segment: 'api-v1' }, (err, result) => { if (err) return reply.send(err) if (result) return reply.send(result.item) reply.send({ notFound: true }) } ) }) ``` -------------------------------- ### Minimal Fastify Caching Setup Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/usage-examples.md Registers the caching plugin with default settings. This enables caching without specific cache control headers. ```javascript const fastify = require('fastify')() const fastifyCaching = require('@fastify/caching') fastify.register(fastifyCaching) fastify.get('/', (req, reply) => { reply.send({ hello: 'world' }) }) fastify.listen({ port: 3000 }) ``` -------------------------------- ### Basic Cache Operations with Fastify Caching Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/usage-examples.md Demonstrates how to register the plugin, get data from cache, and set data to cache with a specified TTL. Handles cache hits and misses. ```javascript fastify.register(fastifyCaching) fastify.get('/fetch-user/:id', (req, reply) => { const userId = req.params.id const cacheKey = `user:${userId}` fastify.cache.get(cacheKey, (err, cached) => { if (err) return reply.send(err) if (cached) { // Cache hit return reply.send({ user: cached.item, fromCache: true, cachedFor: `${cached.ttl}ms` }) } // Cache miss: fetch and store const user = { id: userId, name: 'John Doe', email: 'john@example.com' } fastify.cache.set(cacheKey, user, 300000, (err) => { if (err) return reply.send(err) reply.send({ user, fromCache: false }) }) }) }) ``` -------------------------------- ### Server-Side Cache Interaction Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/quick-reference.md This example shows how to interact with a server-side cache using `fastify.cache.get` and `fastify.cache.set`. It retrieves data from the cache, or computes and stores it if not found, with a TTL of 1 hour. ```javascript fastify.get('/data', (req, reply) => { fastify.cache.get('my-data', (err, cached) => { if (err) return reply.send(err) if (cached) { return reply.send(cached.item) } const data = { value: 'expensive computation' } fastify.cache.set('my-data', data, 3600000, (err) => { if (err) return reply.send(err) reply.send(data) }) }) }) ``` -------------------------------- ### Server-Local Cache with Abstract-Cache and Redis Source: https://github.com/fastify/fastify-caching/blob/main/README.md Configure a server-local cache using abstract-cache and Redis. This example shows how to register the plugin with a custom cache instance and use `fastify.cache.set` to store data. It does not set cache-control headers on responses. ```javascript const IORedis = require('ioredis') const redis = new IORedis({host: '127.0.0.1'}) const abcache = require('abstract-cache')({ useAwait: false, driver: { name: 'abstract-cache-redis', // must be installed via `npm i` options: {client: redis} } }) const fastify = require('fastify')() fastify .register(require('@fastify/redis'), {client: redis}) .register(require('@fastify/caching'), {cache: abcache}) fastify.get('/', (req, reply) => { fastify.cache.set('hello', {hello: 'world'}, 10000, (err) => { if (err) return reply.send(err) reply.send({hello: 'world'}) }) }) fastify.listen({ port: 3000 }, (err) => { if (err) throw err }) ``` -------------------------------- ### Register Fastify Caching Plugin Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/protocol-and-compatibility.md Demonstrates standard, callback, and async context registration of the fastify-caching plugin. Ensure you have installed the plugin using npm or yarn. ```javascript const fastify = require('fastify')() const fastifyCaching = require('@fastify/caching') // Standard registration await fastify.register(fastifyCaching, options) // With callback fastify.register(fastifyCaching, options, (err) => { if (err) throw err }) // In async context await fastify.register(async (instance) => { await instance.register(fastifyCaching, options) }) ``` -------------------------------- ### Access Cache via Instance Decoration Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/hooks-and-internals.md Use `fastify.cache.get()` to retrieve cached data and `fastify.cache.set()` to store it. This example demonstrates a cache miss scenario where data is fetched and then stored. ```javascript fastify.get('/user/:id', (req, reply) => { // Access cache via instance decoration fastify.cache.get(`user:${req.params.id}`, (err, result) => { if (result) { return reply.send(result.item) } // Cache miss: fetch and store const user = { id: req.params.id, name: 'John' } fastify.cache.set( `user:${req.params.id}`, user, 3600000, (err) => { reply.send(user) } ) }) }) ``` -------------------------------- ### Application-Level Cache Error Handling in Fastify Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/errors.md Handle cache errors directly within your route handlers. This example demonstrates fetching data directly when a cache 'get' operation fails, and handling cache misses by fetching, storing, and then responding. ```javascript fastify.get('/users/:id', (req, reply) => { fastify.cache.get(`user:${req.params.id}`, (err, cached) => { if (err) { // Cache error: fetch directly console.warn('Cache get error:', err) return reply.send({ id: req.params.id, cached: false }) } if (cached?.item) { // Cache hit return reply.send({ ...cached.item, cached: true }) } // Cache miss: fetch and store const user = fetchUser(req.params.id) fastify.cache.set(`user:${req.params.id}`, user, 3600000, (setErr) => { if (setErr) console.warn('Cache set error:', setErr) reply.send({ ...user, cached: false }) }) }) }) ``` -------------------------------- ### Custom ETag Header Formats Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/protocol-and-compatibility.md Examples of custom ETag header formats that can be used for more descriptive versioning. ```text ETag: "article-rev-42" ``` ```text ETag: "sha256-abc123def456" ``` -------------------------------- ### Expires Header Example Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/protocol-and-compatibility.md An example of the Expires header formatted according to RFC 2616, indicating a specific expiration date and time. ```text Expires: Wed, 21 Oct 2025 07:28:00 GMT ``` -------------------------------- ### Basic Fastify Caching Setup Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/README.md Register the fastify-caching plugin with public privacy and a 1-hour expiration. This snippet demonstrates how to set up basic caching for API routes. ```javascript const fastify = require('fastify')() const fastifyCaching = require('@fastify/caching') await fastify.register(fastifyCaching, { privacy: 'public', expiresIn: 3600 }) fastify.get('/api', (req, reply) => { reply.etag('unique-tag').send({ data: 'value' }) }) ``` -------------------------------- ### Handling Multiple ETags in If-None-Match Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/protocol-and-compatibility.md This example shows the format for multiple ETags in the If-None-Match header. Note that the plugin only supports exact tag matching and does not handle multiple ETag comparisons. ```http If-None-Match: "tag1", "tag2", "tag3" ``` -------------------------------- ### Disable Client-Side Caching with Fastify Source: https://github.com/fastify/fastify-caching/blob/main/README.md Register the plugin with privacy set to NOCACHE to prevent client-side caching for all routes. This example demonstrates how to configure the plugin and then makes an HTTP GET request to observe the cache-control header. ```javascript const http = require('node:http') const fastify = require('fastify')() const fastifyCaching = require('@fastify/caching') fastify.register( fastifyCaching, {privacy: fastifyCaching.privacy.NOCACHE}, (err) => { if (err) throw err } ) fastify.get('/', (req, reply) => { reply.send({hello: 'world'}) }) fastify.listen({ port: 3000 }, (err) => { if (err) throw err http.get('http://127.0.0.1:3000/', (res) => { console.log(res.headers['cache-control']) }) }) ``` -------------------------------- ### Combine Expires Header with Cache-Control Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/api-reference.md This example shows how to chain the expires() method with the header() method to set both Expires and Cache-Control headers. This is useful for fine-grained cache control. ```javascript fastify.get('/cached', (req, reply) => { const expiresAt = new Date(Date.now() + 3600000) // 1 hour reply .expires(expiresAt) .header('Cache-Control', 'public, max-age=3600') .send({ resource: 'data' }) }) ``` -------------------------------- ### Configure Fastify Caching with Public Privacy Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/api-reference.md Example of registering the fastify-caching plugin with the 'privacy' option set to 'public' and specifying an 'expiresIn' value. ```javascript const fastifyCaching = require('@fastify/caching') fastify.register(fastifyCaching, { privacy: fastifyCaching.privacy.PUBLIC, expiresIn: 3600 }) ``` -------------------------------- ### Programmatic Cache Set with Default and Custom Segments Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/configuration.md Demonstrates setting cache entries using the callback-based API. The first example uses the default segment, while the second shows how to explicitly override the segment for a specific cache entry. ```javascript // Callback-based (default) fastify.cache.set('key', value, 60000, (err) => {}) // Stored as: { id: 'key', segment: 'my-api' } // With segment object fastify.cache.set({ id: 'key', segment: 'other' }, value, 60000, (err) => {}) // Stored with explicit segment override ``` -------------------------------- ### Conditional Request Example with ETag Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/hooks-and-internals.md Illustrates the interaction between a client sending an If-None-Match header and the server responding with either a 200 OK (with ETag) or a 304 Not Modified. ```http // First request GET /api/data HTTP/1.1 Response (from route): HTTP/1.1 200 OK ETag: "data-v1" Content-Type: application/json { "id": 1, "value": "data" } // Second request (within ETag TTL) GET /api/data HTTP/1.1 If-None-Match: "data-v1" Response (from plugin): HTTP/1.1 304 Not Modified (no body sent, client uses cached version) ``` -------------------------------- ### Generate Content-Based ETag Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/quick-reference.md This example demonstrates how to generate an ETag based on the content of the response using SHA256 hashing. The ETag is then attached to the response using `reply.etag()`. ```javascript const crypto = require('crypto') fastify.get('/api', (req, reply) => { const data = { id: 1, name: 'test' } const etag = crypto .createHash('sha256') .update(JSON.stringify(data)) .digest('hex') reply.etag(etag).send(data) }) ``` -------------------------------- ### ETag with Custom Cache Lifetime Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/api-reference.md Set a specific cache lifetime in milliseconds for the ETag. This example sets the cache to expire after 5 seconds. ```javascript fastify.get('/volatile', (req, reply) => { reply.etag('unique-value-123', 5000).send({ data: 'expires quickly' }) }) ``` -------------------------------- ### Handle cache.get() Errors Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/errors.md Implement a custom error handler to manage errors during cache retrieval. This example shows a fallback strategy to serve an uncached response when a 'Connection refused' error occurs. ```javascript const mockCache = { get: (_info, callback) => { callback(new Error('Connection refused')) }, set: (_key, _value, _ttl, callback) => callback() } fastify.register(fastifyCaching, { cache: mockCache }) fastify.get('/test', (req, reply) => { reply.send({ ok: true }) }) // Any request results in HTTP 500 with the cache error ``` ```javascript fastify.setErrorHandler((error, request, reply) => { if (error.message.includes('Connection refused')) { // Fallback strategy: serve uncached response return reply.status(200).send({ cached: false, data: {} }) } reply.send(error) }) ``` -------------------------------- ### Checking Plugin Registration Status Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/protocol-and-compatibility.md Provides an example of how to check if the Fastify Caching plugin has been successfully registered using its internal symbol within an onRequest hook. ```javascript fastify.addHook('onRequest', async function() { if (this[Symbol.for('fastify-caching.registered')] === true) { // Plugin is registered } }) ``` -------------------------------- ### Set ETag and Lifetime with reply.etag() Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/hooks-and-internals.md This example demonstrates how to use `reply.etag()` to set both the ETag header and an internal property `_etagLife` which is used by the onSend hook for cache management. The lifetime is specified in milliseconds. ```javascript fastify.get('/resource', (req, reply) => { // reply.etag() sets both header and _etagLife reply .etag('content-hash-123', 600000) // 10 minutes .send({ data: 'value' }) }) ``` -------------------------------- ### get(key) (async version) Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/types.md Retrieves a cached item asynchronously using Promises and async/await. This method is available when the cache driver is configured with `useAwait: true`. It returns a Promise that resolves to a CacheResult object or null if the item is not found or has expired. ```APIDOC ## get(key) (async version) ### Description Retrieves a cached item asynchronously using Promises and async/await. Available when the cache driver is configured with `useAwait: true`. ### Method GET ### Endpoint N/A (SDK Method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```javascript async function getUser(id) { const result = await fastify.cache.get(`user:${id}`) if (result) { return result.item } return null } ``` ### Response #### Success Response (Promise | null>) - Resolves to a `CacheResult` object containing the cached item, or `null` if not found or expired. #### Response Example ```json { "item": "cached data", "stored": 1678886400000, "ttl": 60000 } ``` ``` -------------------------------- ### Handle cache.set() Errors Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/errors.md Handle errors that occur when storing data in the cache, such as exceeding cache quotas. This example demonstrates logging the error and serving the response anyway. ```javascript const mockCache = { get: (_info, callback) => callback(null, null), set: (_key, _value, _ttl, callback) => { callback(new Error('Cache quota exceeded')) } } fastify.register(fastifyCaching, { cache: mockCache }) fastify.get('/test', (req, reply) => { reply.etag('123').send({ data: 'value' }) }) // Response returns HTTP 500 with the error ``` ```javascript fastify.setErrorHandler((error, request, reply) => { if (error.message.includes('quota')) { // Log and serve response anyway console.warn('Cache quota exceeded, serving uncached') return reply.status(200).send(/* payload */) } reply.send(error) }) ``` -------------------------------- ### Handle Cache Errors Gracefully with Fastify Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/usage-examples.md Implement a custom error handler to gracefully manage cache-related errors, such as connection refusals. This allows the application to serve fresh content when the cache is unavailable. It also shows individual error handling for cache get and set operations. ```javascript fastify.register(fastifyCaching, { cache: customCache }) fastify.setErrorHandler((error, request, reply) => { // Check if error came from cache operation if (error.message && error.message.includes('ECONNREFUSED')) { // Cache server unavailable, serve without caching console.warn('Cache unavailable, serving fresh') reply.status(200).send({ cached: false, data: {} }) } else { // Other errors reply.send(error) } }) fastify.get('/resilient', (req, reply) => { fastify.cache.get('key', (err, cached) => { if (err) { // Individual error handling console.warn('Cache get failed:', err) return reply.send({ data: 'fresh', cached: false }) } if (cached) { return reply.send({ ...cached.item, cached: true }) } const data = { value: 'fresh' } fastify.cache.set('key', data, 3600000, (err) => { if (err) console.warn('Cache set failed:', err) reply.send({ ...data, cached: false }) }) }) }) ``` -------------------------------- ### get(key, callback) Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/types.md Retrieves a cached item using a callback function. The callback receives an error object if an issue occurs, or a CacheResult object containing the cached item, its storage timestamp, and its time-to-live. ```APIDOC ## get(key, callback) ### Description Retrieves a cached item using a callback function. ### Method GET ### Endpoint N/A (SDK Method) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```javascript fastify.cache.get('user:123', (err, result) => { if (err) throw err if (result) { console.log(result.item) // The cached value console.log(result.stored) // Timestamp when stored console.log(result.ttl) // Time to live in milliseconds } }) // With segment fastify.cache.get({ id: 'key', segment: 'users' }, (err, result) => { if (err) throw err if (result) { console.log(result.item) } }) ``` ### Response #### Success Response (void) - The callback function is invoked with `(error, result)`. #### Response Example N/A (Callback-based) ``` -------------------------------- ### Implement Cache Callbacks Correctly in fastify-caching Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/errors.md Custom cache drivers must always invoke the provided callback to prevent deadlocks. This example shows a 'badCache' that misses the callback and a 'goodCache' that invokes it properly. ```javascript const badCache = { get: (_info, callback) => { // Missing callback invocation }, set: (_key, _value, _ttl, callback) => { callback() } } // This will hang fastify.register(fastifyCaching, { cache: badCache }) ``` ```javascript const goodCache = { get: (_info, callback) => { try { const value = /* fetch from cache */ callback(null, value) } catch (err) { callback(err) } }, set: (_key, _value, _ttl, callback) => { try { /* store in cache */ callback(null) } catch (err) { callback(err) } } } ``` -------------------------------- ### Import and Use Fastify Caching Module Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/quick-reference.md Import the main function and access aliases or privacy constants. Use the main function with an instance, options, and a callback. ```javascript const fastifyCaching = require('@fastify/caching') // Main function fastifyCaching(instance, options, next) // Aliases fastifyCaching.default fastifyCaching.fastifyCaching // Privacy constants fastifyCaching.privacy.NOCACHE // 'no-cache' fastifyCaching.privacy.PRIVATE // 'private' fastifyCaching.privacy.PUBLIC // 'public' ``` -------------------------------- ### AbstractCacheCompliantObject Interface Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/quick-reference.md Defines the interface for cache-compliant objects, specifying `get` and `set` methods for interacting with the cache. ```APIDOC ## Interface: AbstractCacheCompliantObject ### Description This interface defines the contract for objects that can be used as a cache. It includes methods for retrieving (`get`) and storing (`set`) data. ### Methods #### get Retrieves an item from the cache. - **Parameters** - `key` (string | { id: string; segment: string }) - The key to retrieve the item with. Can be a string or an object with `id` and `segment`. - `callback` (function, optional) - A callback function that receives an error and the cache result. - **Returns** - `void | Promise>` - Returns void if a callback is provided, otherwise returns a Promise resolving to the cache result. #### set Stores an item in the cache. - **Parameters** - `key` (string | { id: string; segment: string }) - The key to store the item with. Can be a string or an object with `id` and `segment`. - `value` (unknown) - The value to store in the cache. - `timeToLive` (number) - The time-to-live for the cache item in seconds. - `callback` (function, optional) - A callback function that receives an error. - **Returns** - `void` - This method does not return a value. ``` -------------------------------- ### Register Fastify Caching Plugin Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/api-reference.md Register the fastify-caching plugin with a no-cache policy. This is the basic setup for enabling caching functionality. ```javascript const fastify = require('fastify')() const fastifyCaching = require('@fastify/caching') fastify.register(fastifyCaching, { privacy: fastifyCaching.privacy.NOCACHE }) fastify.get('/', (req, reply) => { reply.send({ hello: 'world' }) }) ``` -------------------------------- ### Abstract-Cache Protocol: Callback Mode Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/protocol-and-compatibility.md Shows how to use the cache.get and cache.set methods with callbacks, as defined by the abstract-cache protocol when useAwait is false. ```javascript cache.get(key, (err, result) => {}) cache.set(key, value, ttl, (err) => {}) ``` -------------------------------- ### Initialize Cache Correctly with fastify-caching Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/errors.md Ensure the cache object provided to fastify-caching implements the required interface. Use an abstract-cache instance for proper initialization. ```javascript // Wrong await fastify.register(fastifyCaching, { cache: {} }) // Correct: provide proper abstract-cache instance const abstractCache = require('abstract-cache') await fastify.register(fastifyCaching, { cache: abstractCache() }) ``` -------------------------------- ### AbstractCacheCompliantObject Interface Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/quick-reference.md Defines the interface for cache-compliant objects, specifying methods for getting and setting cache items. Supports both callback and Promise-based operations. ```typescript interface AbstractCacheCompliantObject { get( key: string | { id: string; segment: string }, callback?: (error: unknown, result: CacheResult) => void ): void | Promise>; set( key: string | { id: string; segment: string }, value: unknown, timeToLive: number, callback?: (error: unknown) => void ): void; } type CacheResult = { item: T, stored: number, ttl: number } | null ``` -------------------------------- ### Custom Cache with Redis via abstract-cache Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/usage-examples.md Integrate @fastify/caching with a custom Redis cache implementation using the abstract-cache library. ```javascript const fastify = require('fastify')() const fastifyCaching = require('@fastify/caching') const abstractCache = require('abstract-cache') const IORedis = require('ioredis') const redis = new IORedis({ host: 'localhost', port: 6379 }) const cache = abstractCache({ useAwait: false, driver: { name: 'abstract-cache-redis', options: { client: redis } } }) fastify.register(fastifyCaching, { privacy: 'public', expiresIn: 3600, cache }) fastify.get('/cached-data', (req, reply) => { reply.etag('data-v1').send({ data: 'persisted in redis' }) }) fastify.listen({ port: 3000 }) ``` -------------------------------- ### Get Cached Item with Async/Await Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/types.md Retrieve a cached item using promises and async/await. This is available when the cache driver is configured with `useAwait: true`. ```javascript async function getUser(id) { const result = await fastify.cache.get(`user:${id}`) if (result) { return result.item } return null } ``` -------------------------------- ### Module Export Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/quick-reference.md How to require and use the main function and its aliases, as well as privacy constants. ```APIDOC ## Module Export ```javascript const fastifyCaching = require('@fastify/caching') // Main function fastifyCaching(instance, options, next) // Aliases fastifyCaching.default fastifyCaching.fastifyCaching // Privacy constants fastifyCaching.privacy.NOCACHE // 'no-cache' fastifyCaching.privacy.PRIVATE // 'private' fastifyCaching.privacy.PUBLIC // 'public' ``` ``` -------------------------------- ### Configuration Options Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/quick-reference.md Details on the available configuration options for the fastify-caching plugin. ```APIDOC ## Configuration Options ```javascript { // Cache control policy for responses privacy: undefined | 'public' | 'private' | 'no-cache' | 'no-store' | string, // Client cache expiration (seconds) expiresIn: undefined | number, // Shared cache (CDN) expiration (seconds) - only with privacy:'public' serverExpiresIn: undefined | number, // Cache implementation cache: undefined | AbstractCacheCompliantObject, // Cache segment identifier cacheSegment: '@fastify/caching' | string, // Reserved (unused) etagMaxLife: undefined | number } ``` ``` -------------------------------- ### Get Cached Item with Callback Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/types.md Use this method to retrieve a cached item using a callback function. The callback receives an error or the cache result. ```javascript fastify.cache.get('user:123', (err, result) => { if (err) throw err if (result) { console.log(result.item) // The cached value console.log(result.stored) // Timestamp when stored console.log(result.ttl) // Time to live in milliseconds } }) ``` ```javascript // With segment fastify.cache.get({ id: 'key', segment: 'users' }, (err, result) => { if (err) throw err if (result) { console.log(result.item) } }) ``` -------------------------------- ### Instance Decorations Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/quick-reference.md Information about the properties decorated onto the Fastify instance by the caching plugin. ```APIDOC ## Instance Decorations ```javascript fastify.cache // Cache instance (AbstractCacheCompliantObject) fastify.cacheSegment // Segment string used for ETag storage fastify.etagMaxLife // Reserved, typically undefined ``` ``` -------------------------------- ### Use Custom Cache Implementation Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/api-reference.md Integrate a custom cache implementation, such as one using abstract-cache with Redis. Ensure the cache driver is correctly configured. ```javascript const fastify = require('fastify')() const fastifyCaching = require('@fastify/caching') const abstractCache = require('abstract-cache') const cache = abstractCache({ useAwait: false, driver: { name: 'abstract-cache-redis', options: { client: redisClient } } }) fastify.register(fastifyCaching, { cache }) ``` -------------------------------- ### Abstract-Cache Protocol: Key Formats Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/protocol-and-compatibility.md Demonstrates using simple string keys and object keys with a segment for cache operations. The plugin specifically uses object keys with segments for ETag operations. ```javascript // String key cache.get('user:123', callback) // Object key with segment cache.get({ id: 'user:123', segment: 'users' }, callback) // Plugin uses this format for ETags cache.get({ id: etag, segment: cacheSegment }, callback) cache.set({ id: etag, segment: cacheSegment }, true, ttl, callback) ``` -------------------------------- ### Abstract-Cache Protocol: Promise Mode Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/protocol-and-compatibility.md Illustrates using the cache.get and cache.set methods with promises (async/await), as defined by the abstract-cache protocol when useAwait is true. ```javascript const result = await cache.get(key) await cache.set(key, value, ttl) ``` -------------------------------- ### Fastify Instance Decorations for Caching Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/quick-reference.md Lists the properties decorated onto the Fastify instance by the @fastify/caching plugin, providing access to the cache instance, segment, and ETag max life. ```javascript fastify.cache // Cache instance (AbstractCacheCompliantObject) fastify.cacheSegment // Segment string used for ETag storage fastify.etagMaxLife // Reserved, typically undefined ``` -------------------------------- ### Plugin Options Source: https://github.com/fastify/fastify-caching/blob/main/README.md The @fastify/caching plugin accepts an options object for configuration. Key options include privacy settings, expiration times, cache driver, and cache segment. ```APIDOC ## Options *@fastify/caching* accepts the options object: ```js { privacy: 'value', expiresIn: 300, cache: {get, set}, cacheSegment: 'segment-name' } ``` + `privacy` (Default: `undefined`): can be set to any string that is valid for a *cache-response-directive* as defined by RFC 2616. + `expiresIn` (Default: `undefined`): a value, in seconds, for the *max-age* the resource may be cached. When this is set, and `privacy` is not set to `no-cache`, then `', max-age='` will be appended to the `cache-control` header. + `cache` (Default: `abstract-cache.memclient`): an [abstract-cache][acache] protocol-compliant cache object. Note: the plugin requires a cache instance to properly support the ETag mechanism. Therefore, if a falsy value is supplied the default will be used. + `cacheSegment` (Default: `'@fastify/caching'`): segment identifier to use when communicating with the cache. + `serverExpiresIn` (Default: `undefined`): a value, in seconds, for the length of time the resource is fresh and may be held in a shared cache (e.g. a CDN). Shared caches will ignore max-age when this is specified, though browsers will continue to use max-age. Should be used with expiresIn, not in place of it. When this is set, and `privacy` is set to `public`, then `', s-maxage='` will be appended to the `cache-control` header. [acache]: https://www.npmjs.com/package/abstract-cache ``` -------------------------------- ### Register Fastify Caching Plugin with Custom Redis Implementation (Async/Await) Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/configuration.md Integrate a custom cache implementation, such as Redis via abstract-cache, configured for async/await style using promises. ```javascript const cache = abstractCache({ useAwait: true, // Use promises driver: { name: 'abstract-cache-redis', options: { client: redis } } }) // Now fastify.cache.get() returns a Promise const result = await fastify.cache.get('key') ``` -------------------------------- ### ETag with Method Chaining Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/api-reference.md Demonstrates chaining the reply.etag() method with other Fastify reply methods like header() and send() for concise response construction. ```javascript fastify.get('/chained', (req, reply) => { reply .etag('tag-value') .header('X-Custom', 'value') .send({ content: 'data' }) }) ``` -------------------------------- ### Instance Decorations Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/hooks-and-internals.md Properties added to the Fastify instance for accessing cache functionalities within route handlers. ```APIDOC ## Instance Decorations Properties added to the `fastify` instance via `instance.decorate()`: - `cache` (AbstractCacheCompliantObject): Access cache in route handlers: `fastify.cache.get()`, `fastify.cache.set()` - `cacheSegment` (string): Segment identifier used by plugin for ETag storage. - `etagMaxLife` (number | undefined): Reserved for future use (currently unused). ### Example ```javascript fastify.get('/user/:id', (req, reply) => { // Access cache via instance decoration fastify.cache.get(`user:${req.params.id}`, (err, result) => { if (result) { return reply.send(result.item) } // Cache miss: fetch and store const user = { id: req.params.id, name: 'John' } fastify.cache.set( `user:${req.params.id}`, user, 3600000, (err) => { reply.send(user) } ) }) }) ``` ``` -------------------------------- ### Custom Cache with Async Cache Implementation Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/usage-examples.md Utilize @fastify/caching with an asynchronous cache driver, enabling the use of await for cache operations. ```javascript const cache = abstractCache({ useAwait: true, // Enable promise-based API driver: { name: 'abstract-cache-redis', options: { client: redis } } }) fastify.register(fastifyCaching, { cache }) fastify.get('/async-cache', async (req, reply) => { // Can use await with async cache const cached = await fastify.cache.get('key') if (cached) { return reply.send(cached.item) } const data = await fetchData() await fastify.cache.set('key', data, 3600000) reply.send(data) }) ``` -------------------------------- ### FastifyCachingPluginOptions Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/types.md Configuration object passed to the `fastifyCaching` plugin during registration. All properties are optional and have sensible defaults. ```APIDOC ## FastifyCachingPluginOptions ### Description Configuration object passed to the `fastifyCaching` plugin during registration. All properties are optional and have sensible defaults. ### Properties | Property | Type | Required | Default | Description | |----------|------|----------|---------|-------------| | cache | AbstractCacheCompliantObject | No | abstract-cache memclient | An abstract-cache protocol-compliant cache instance. If falsy, the default LRU in-memory cache is used. The plugin requires this cache to support ETag lookups. | | cacheSegment | string | No | '@fastify/caching' | Segment identifier passed to the cache when storing/retrieving items. Allows multiple cache segments for different cache strategies within the same instance. | | etagMaxLife | number | No | undefined | Reserved for future use. Not currently utilized in the plugin. | | expiresIn | number | No | undefined | Cache duration in seconds for client caches (max-age). When set with privacy not equal to 'no-cache', appends `', max-age='` to the Cache-Control header. | | privacy | string | No | undefined | Cache control privacy directive (e.g., 'public', 'private', 'no-cache', 'no-store'). Any RFC 2616 ยง14.9 valid directive string is accepted. When set, defines the Cache-Control header value. | | serverExpiresIn | number | No | undefined | Cache duration in seconds for shared caches like CDNs (s-maxage). Only appended to Cache-Control header when privacy is 'public' and this option is set. Use alongside expiresIn. | ### Usage ```javascript const fastify = require('fastify')() const fastifyCaching = require('@fastify/caching') await fastify.register(fastifyCaching, { privacy: 'public', expiresIn: 3600, serverExpiresIn: 86400, cacheSegment: 'api-cache', cache: customCacheInstance }) ``` ``` -------------------------------- ### Get Cache Item (Callback) Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/quick-reference.md Retrieve a cached item using its key. Handles segments for organized caching. The callback receives an error or a result object containing the item, stored timestamp, and TTL. ```javascript fastify.cache.get('key', (err, result) => { if (err) {} if (result) { result.item // The cached value result.stored // Timestamp (ms) result.ttl // Time to live (ms) } }) // With segment fastify.cache.get({ id: 'key', segment: 'users' }, (err, result) => {}) ``` -------------------------------- ### Creating Default Cache Instance Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/protocol-and-compatibility.md When no cache option is provided to fastify-caching, it defaults to using abstract-cache's in-memory LRU client. This is suitable for development and testing but not recommended for production. ```javascript const defaultCache = require('abstract-cache')() ``` -------------------------------- ### Set Expires Header with Cache-Control Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/usage-examples.md Configure both the Expires header and Cache-Control directive for caching. This example registers the plugin with public privacy and a max-age of 3600 seconds, and also sets an absolute expiration time for the Expires header, resulting in dual caching mechanisms. ```javascript fastify.register(fastifyCaching, { privacy: 'public', expiresIn: 3600 }) fastify.get('/dual-cache', (req, reply) => { const expiresAt = new Date() expiresAt.setHours(expiresAt.getHours() + 1) reply .expires(expiresAt) .send({ data: 'cached via both mechanisms' }) }) // Response has both: // Cache-Control: public, max-age=3600 // Expires: Wed, 21 Oct 2025 17:28:00 GMT ``` -------------------------------- ### Set Custom ETag Cache Duration Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/usage-examples.md Specify a custom duration for ETag caching. For example, caching an ETag for only 30 seconds ensures that conditional requests within this period receive a 304 status, while requests after this period receive a 200 with the full payload. ```javascript fastify.get('/volatile', (req, reply) => { // Cache ETag for 30 seconds only reply.etag('tag-123', 30000).send({ data: 'changing' }) }) // Within 30 seconds: conditional requests get 304 // After 30 seconds: conditional requests get 200 with full payload ``` -------------------------------- ### Register Fastify Caching Plugin with Custom Redis Implementation (Callbacks) Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/configuration.md Integrate a custom cache implementation, such as Redis via abstract-cache, using callbacks for asynchronous operations. ```javascript const fastify = require('fastify')() const plugin = require('@fastify/caching') const abstractCache = require('abstract-cache') const IORedis = require('ioredis') const redis = new IORedis() const cache = abstractCache({ useAwait: false, // Use callbacks driver: { name: 'abstract-cache-redis', options: { client: redis } } }) await fastify.register(plugin, { cache }) ``` -------------------------------- ### TypeScript Plugin Registration Source: https://github.com/fastify/fastify-caching/blob/main/_autodocs/protocol-and-compatibility.md Shows how to register the Fastify Caching plugin with TypeScript, including type imports and option configuration. ```typescript import fastifyCaching from '@fastify/caching' import type { FastifyCachingPluginOptions } from '@fastify/caching' const options: FastifyCachingPluginOptions = { privacy: 'public', expiresIn: 3600 } await fastify.register(fastifyCaching, options) ```