Caching in GraphQL: Migliorare le Prestazioni con Apollo e Tecniche Avanzate
Il caching è una tecnica essenziale per migliorare le prestazioni delle API GraphQL, riducendo il carico sul server e migliorando l’esperienza utente. In questa guida, esploreremo le diverse tecniche di caching, sia lato client che lato server, che puoi implementare per ottimizzare le prestazioni delle tue API GraphQL.
Perché il Caching è Importante?
Il caching aiuta a evitare richieste ridondanti al server, memorizzando temporaneamente i risultati delle query in modo che possano essere riutilizzati. Questo riduce la latenza, il carico di lavoro sul server, e il consumo di risorse, migliorando l’efficienza complessiva del sistema.
Caching Lato Client con Apollo Client
1. Cache di In-Memory
Apollo Client utilizza una cache in-memory per memorizzare i risultati delle query. Quando viene eseguita una query, Apollo controlla prima la cache per vedere se i dati sono già presenti, evitando richieste ridondanti al server.
Configurazione di Base
Quando configuri Apollo Client, la cache in-memory viene abilitata di default.
import { ApolloClient, InMemoryCache } from "@apollo/client";
const client = new ApolloClient({
uri: "https://your-graphql-endpoint.com/graphql",
cache: new InMemoryCache(),
});
2. Fetch Policies
Le fetch policies controllano come Apollo Client interagisce con la cache e con il server. Le fetch policies più comuni includono:
- cache-first: Usa i dati dalla cache, e solo se non presenti, invia la richiesta al server.
- cache-and-network: Usa i dati dalla cache, ma invia comunque una richiesta al server per aggiornare la cache.
- network-only: Bypassa la cache e invia sempre la richiesta al server.
- no-cache: Non memorizza i risultati nella cache.
Esempio di Fetch Policy
const { loading, error, data } = useQuery(GET_POSTS, {
fetchPolicy: "cache-and-network",
});
3. Scrittura Manuale nella Cache
A volte è utile aggiornare manualmente la cache dopo una mutazione, per evitare richieste aggiuntive al server.
Esempio di Aggiornamento Manuale della Cache
const [addPost] = useMutation(ADD_POST, {
update(cache, { data: { addPost } }) {
const { posts } = cache.readQuery({ query: GET_POSTS });
cache.writeQuery({
query: GET_POSTS,
data: { posts: posts.concat([addPost]) },
});
},
});
Caching Lato Server
1. Cache-Control nelle Risposte HTTP
Puoi aggiungere intestazioni Cache-Control alle risposte HTTP per istruire i client e i proxy su come memorizzare nella cache le risposte.
Esempio con Apollo Server
const { ApolloServer, gql } = require("apollo-server");
const typeDefs = gql`
type Query {
posts: [Post]
}
type Post {
id: ID!
title: String!
content: String!
}
`;
const resolvers = {
Query: {
posts: () => {
// Logica per recuperare i post
},
},
};
const server = new ApolloServer({
typeDefs,
resolvers,
cacheControl: {
defaultMaxAge: 10, // Cache di 10 secondi per tutte le risposte
},
});
server.listen().then(({ url }) => {
console.log(`Server pronto su ${url}`);
});
2. Persisted Queries
Le persisted queries sono un metodo per ridurre la quantità di dati inviati in una richiesta GraphQL. Invece di inviare l’intera query, invii un identificatore della query già memorizzata sul server.
Implementazione di Persisted Queries
Apollo Client supporta le persisted queries tramite il pacchetto @apollo/client/link/persisted-queries
.
npm install @apollo/client @apollo/client/link/persisted-queries
Configurazione delle Persisted Queries
import { ApolloClient, InMemoryCache } from "@apollo/client";
import { createPersistedQueryLink } from "@apollo/client/link/persisted-queries";
import { HttpLink } from "@apollo/client";
const httpLink = new HttpLink({ uri: "/graphql" });
const persistedQueriesLink = createPersistedQueryLink().concat(httpLink);
const client = new ApolloClient({
link: persistedQueriesLink,
cache: new InMemoryCache(),
});
3. Redis Cache per Apollo Server
Per implementare una cache distribuita e più persistente, puoi utilizzare Redis con Apollo Server.
Installazione di Redis e Apollo Server Cache Redis
npm install apollo-server-cache-redis ioredis
Configurazione della Cache Redis
const { ApolloServer } = require("apollo-server");
const Redis = require("ioredis");
const { RedisCache } = require("apollo-server-cache-redis");
const redis = new Redis();
const cache = new RedisCache({ redis });
const server = new ApolloServer({
typeDefs,
resolvers,
cache,
});
Best Practices per il Caching
1. Definire una Strategia di Caching
Non tutte le risorse dovrebbero essere memorizzate nella cache allo stesso modo. Definisci una strategia che consideri la frequenza di aggiornamento dei dati e le esigenze dell’applicazione.
2. Usare la Cache con Moderazione
Il caching è potente, ma abusarne può portare a dati obsoleti o inconsistenza. Assicurati di invalidare la cache quando i dati vengono aggiornati.
3. Monitorare le Performance
Usa strumenti di monitoraggio per tenere traccia dell’efficacia del caching. Controlla la cache hit rate e ottimizza in base ai risultati.
4. Implementare la Paginazione e i Limiti di Dati
Evita di memorizzare grandi quantità di dati nella cache. Implementa la paginazione e i limiti di dati per migliorare l’efficienza del caching.
5. Sfruttare le Mutazioni per Aggiornare la Cache
Dopo una mutazione, aggiorna la cache per riflettere i nuovi dati, evitando richieste aggiuntive non necessarie.
Conclusione
Il caching è una tecnica essenziale per ottimizzare le prestazioni delle API GraphQL. Con Apollo Client e Apollo Server, hai a disposizione potenti strumenti per implementare il caching sia lato client che server. Seguendo le best practices delineate in questa guida, sarai in grado di migliorare significativamente l’efficienza delle tue applicazioni GraphQL, riducendo la latenza e il carico sui server.