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.
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 200–299. 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.
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
}
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.