Passa al contenuto principale

Caching

Efesto ha una piccola cache delle risposte integrata, basata su Redis, sullo stack Express. Abiliti Redis una volta nella configurazione, poi dichiari una chiave di cache per endpoint. In caso di cache hit il metodo dell'endpoint viene saltato e il JSON memorizzato viene restituito direttamente.

Solo Express

La cache Redis descritta qui è implementata dall'adapter Express. L'adapter Bun/Elysia non aggiunge caching: lì usa i plugin/pattern di caching nativi di Elysia.

1. Abilita Redis

Aggiungi un blocco redis al config di Efesto. La cache resta disattivata finché non è presente:

efesto({
// ...
options: {
config: {
redis: {
host: "127.0.0.1", // host Redis
port: 6379, // porta Redis
defaultExpiresInSeconds: 600, // TTL di fallback quando un endpoint non ne imposta uno
},
},
},
});

2. Metti in cache un endpoint

Dichiara cache all'interno dell'oggetto _<method>Swagger del metodo. In caso di hit, Efesto restituisce il valore in cache e non esegue mai il tuo metodo:

import { BaseApiService, SwaggerOptions } from "efesto";

class Users extends BaseApiService {
constructor() {
super(__filename);
}

_getSwagger: SwaggerOptions = {
operationId: "getUsers",
cache: {
key: "`users`", // vedi la nota sui backtick qui sotto
expiresInSeconds: 60, // opzionale; ha la precedenza su defaultExpiresInSeconds
},
};

_get(req, res) {
return res.json(listUsers());
}
}
export default Users;

Vengono memorizzate solo le risposte con esito positivo: Efesto salva il corpo quando il codice di stato è nell'intervallo 200299. Il TTL si risolve come expiresInSeconds → config.redis.defaultExpiresInSeconds → 60.

La chiave è un'espressione valutata

Questo è l'unico dettaglio da azzeccare. La stringa key viene valutata come JavaScript al momento della richiesta, con accesso all'oggetto req. È per questo che il valore è racchiuso tra backtick all'interno della stringa: stai scrivendo un template literal come stringa:

cache: {
// una stringa che contiene un template literal con backtick
key: "`user-${req.user.id}-profile`",
}

Per una richiesta in cui req.user.id è 622b8386..., la chiave Redis risultante è user-622b8386...-profile. Una chiave statica come "`users`" ha comunque bisogno dei backtick interni.

Sicurezza

Poiché la chiave passa attraverso eval(), trattala come codice, non come dato. Costruisci le chiavi solo da valori che controlli tu (req.user.id, req.params), mai interpolando input client non sanificato nell'espressione in un modo che potrebbe iniettare codice.

3. Invalida la cache

Un endpoint che modifica i dati elimina le chiavi in cache con purgeKey. Accetta una chiave o un array, ciascuna un'espressione valutata come key:

_postSwagger: SwaggerOptions = {
operationId: "createUser",
purgeKey: ["`users`"], // elimina questa chiave (o chiavi) quando l'endpoint viene eseguito
};

_post(req, res) {
const user = createUser(req.body);
return res.json(user); // la voce "users" in cache viene eliminata durante l'esecuzione
}
Nome della proprietà

La proprietà è purgeKey (purge singolare non funziona). I valori di purgeKey vengono valutati e possono usare i pattern di chiave Redis supportati da KEYS, es. "`user-*`" per eliminare una famiglia di chiavi.

Mettere tutto insieme

Una tipica coppia lettura/scrittura: metti in cache l'elenco, eliminalo alla creazione.

class Users extends BaseApiService {
constructor() { super(__filename); }

_getSwagger: SwaggerOptions = {
operationId: "getUsers",
cache: { key: "`users`", expiresInSeconds: 120 },
};
_get(req, res) { return res.json(listUsers()); }

_postSwagger: SwaggerOptions = {
operationId: "createUser",
purgeKey: ["`users`"],
};
_post(req, res) { return res.json(createUser(req.body)); }
}

Ambito e limiti

La cache di Efesto è volutamente minimale: una chiave per endpoint, un TTL e l'invalidazione delle chiavi. Non fornisce livelli write-through, refresh in background, cache warming, statistiche o endpoint di health. Se ti servono, parla direttamente con Redis nei tuoi handler, oppure usa il client che preferisci insieme a Efesto.