Belajar GraphQL - Client & Server-Side Caching Strategies
Episode 20 of 51

Belajar GraphQL - Client & Server-Side Caching Strategies

Episode 20 membangun arsitektur caching end-to-end: caching server-side dengan cache warming dan invalidation, lapisan cache dari CDN sampai Redis, normalized cache Apollo Client dengan type policies, pola update cache dan eviction, hingga pengenalan GraphQL CDN.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Cache adalah salah satu alat paling efektif untuk mempercepat aplikasi — dan juga salah satu sumber bug paling licik. Episode 20 membangun arsitektur caching end-to-end yang benar: dari sisi server sampai sisi client, dengan pemahaman tentang normalisasi, invalidation, dan eviction. Kita akan membahas caching server-side, lapisan-lapisan cache yang tersedia, normalized cache Apollo Client, cara memperbarui dan meng-evict cache, serta pengenalan GraphQL CDN.

Server-Side Caching

Full Response dan Partial Caching

  • Full response caching: seluruh response query disimpan dan dikembalikan untuk query yang sama. Efektif untuk data publik yang jarang berubah.
  • Partial caching: sebagian field di-cache (field-level, episode 19) dan sisanya diambil langsung.
JSFull response caching di Redis
async function cachedQuery(operation, key) {
  const cached = await ctx.redis.get(key);
  if (cached) return JSON.parse(cached);
 
  const result = await execute(operation);
  await ctx.redis.set(key, JSON.stringify(result), "EX", 60);
  return result;
}

Cache Warming dan Invalidation

  • TTL (time-to-live): data kadaluarsa otomatis setelah jangka waktu tertentu.
  • Event-based: cache dihapus/di-update saat mutation mengubah data terkait.
JSInvalidation saat mutation
async function createPost(_, args, ctx) {
  const post = await ctx.db.posts.create(args.input);
  await ctx.redis.del("feed:home");
  await ctx.redis.del(`posts:${args.input.authorId}`);
  return post;
}

Cache Layers

CDN, Aplikasi, dan Database

  • CDN (Cloudflare, Fastly): menyimpan response di edge, terbaik untuk data publik.
  • Application-level cache: hasil query atau field di memori aplikasi (Redis, Memcached).
  • Database query cache: cache hasil query database untuk pola akses yang berulang.
Jalankan Redis via Docker
docker run -d -p 6379:6379 redis:7

Praktik umum: gabungkan lapisan dengan aturan — cache hasil query untuk data publik di CDN, data autentikasi dan per-user di Redis (jalankan via docker run -d -p 6379:6379 redis:7), dan hindari cache di level aplikasi yang sulit di-invalidate secara terpusat.

Client-Side Caching

Apollo Client InMemoryCache

Sisi client punya cache sendiri — ini yang membuat UI terasa instan. Apollo Client menyimpan hasil query dalam normalized cache, menyimpan setiap objek sekali berdasarkan __typename dan id:

JSSetup InMemoryCache
import { ApolloClient, InMemoryCache } from "@apollo/client";
 
const client = new ApolloClient({
  uri: "http://localhost:4000",
  cache: new InMemoryCache({
    typePolicies: {
      Query: {
        fields: {
          posts: {
            keyArgs: ["category"],
          },
        },
      },
    },
  }),
});

Normalized cache menyimpan setiap objek sekali berdasarkan __typename dan id, lalu menghubungkannya — sehingga dua query yang berbagi objek yang sama otomatis berbagi data tanpa fetch ulang.

Cache Policies

  • cache-first (default): gunakan cache bila ada, network hanya jika kosong.
  • cache-only: hanya cache, tanpa network.
  • network-only: selalu jaringan, abaikan cache.
  • cache-and-network (default untuk UI feed): tampilkan cache segera lalu update dari jaringan.

Cache Normalization

Type Policies dan Custom Cache ID

Normalisasi bekerja dengan menggabungkan __typename dan id. Untuk tipe tanpa id, konfigurasi keyFields agar tetap bisa dinormalisasi. Tanpa key yang stabil, query yang sama akan di-fetch berulang — penyebab umum "cache tidak berfungsi" di Apollo Client:

JSCustom cache ID
const cache = new InMemoryCache({
  typePolicies: {
    Review: {
      keyFields: ["id"],
    },
    Person: {
      keyFields: ["firstName", "lastName"],
    },
  },
});

Tanpa key yang stabil, objek tidak dinormalisasi dan query yang sama akan di-fetch berulang. Ini penyebab umum "cache tidak berfungsi" di Apollo Client.

Cache Updates dan Eviction

Memperbarui Cache Setelah Mutation

  • Refetch: jalankan ulang query yang terpengaruh — sederhana tapi boros.
  • Cache write: update cache secara langsung dari hasil mutation.
JSUpdate cache setelah mutation
const [createPost] = useMutation(CREATE_POST, {
  update(cache, { data }) {
    const existing = cache.readQuery({ query: GET_POSTS });
    cache.writeQuery({
      query: GET_POSTS,
      data: {
        posts: [data.createPost, ...existing.posts],
      },
    });
  },
});

Eviction dan Optimistic UI

Untuk membuang data dari cache (misalnya saat logout), panggil cache.evict dan cache.gc:

JSEvict dan garbage collect
client.cache.evict({ id: `User:${userId}` });
client.cache.gc();

Optimistic UI menampilkan perubahan sementara sebelum server menjawab (episode 5): Apollo menyimpan hasil optimistik di cache, lalu menggantinya dengan hasil asli saat mutation selesai. Ini memberikan pengalaman UI yang instan.

GraphQL CDN

Stella dan GraphCDN

GraphQL CDN menyimpan hasil query di edge network, sehingga latensi menurun drastis untuk pengguna global. Layanan seperti Stella (Netlify) dan GraphCDN menghubungkan langsung ke origin GraphQL:

Setup GraphCDN via CLI
npx graphcdn push

Konfigurasi biasanya berupa file YAML yang menandai query mana yang boleh di-cache dan aturan purging:

graphcdn.yml
originUrl: https://api.kalian.com
scopes:
  - operationName: HomeFeed
    maxAge: 60

Cache di CDN di-purge saat data berubah — biasanya lewat webhook dari mutation. Ini melengkapi arsitektur caching: CDN di depan, Redis di tengah, dan normalized cache di client.

Penutup

Inti yang harus dibawa pulang:

  • Cache server-side terdiri dari full response dan partial caching dengan invalidation event-based.
  • Lapisan cache berjenjang: CDN untuk publik, Redis untuk data per-user.
  • Apollo Client memakai normalized cache dengan type policies dan keyFields.
  • Cache policies mengontrol keseimbangan kecepatan dan kesegaran data.
  • Update cache manual dan optimistic UI menjaga UI tetap konsisten.
  • GraphQL CDN membawa cache ke edge untuk latensi global yang rendah.

Di episode 21 selanjutnya kalian akan mempelajari testing GraphQL — test pyramid, unit testing resolver dengan mock, integration testing dengan apollo-server testing dan supertest, schema testing dengan GraphQL Inspector, mocking data, hingga E2E testing dengan Cypress. Kualitas API kalian akan teruji dari unit sampai end-to-end!