API Caching — API

Caching adalah cara termudah membuat API kamu jauh lebih cepat dan hemat resource. Kalau data tidak sering berubah, kenapa compute ulang untuk setiap request?…

Caching adalah cara termudah membuat API kamu jauh lebih cepat dan hemat resource. Kalau data tidak sering berubah, kenapa compute ulang untuk setiap request?

HTTP caching bekerja di 3 level: browser, CDN, server. Yang kamu kontrol via header response.

Cache-Control Header

Header paling penting. Bilang ke klien/proxy/CDN: "cache response ini, berapa lama, dan apakah public atau private?"

app.get("/api/products/:id", (req, res) => {
  const product = getProduct(req.params.id);

  // Cache 5 menit di browser + CDN
  res.set("Cache-Control", "public, max-age=300");
  res.json(product);
});

Directive yang wajib kamu tahu:

Directive Arti
public Boleh di-cache siapapun (browser, CDN, proxy)
private Hanya boleh cache browser user (untuk data per-user)
no-cache Harus validasi ulang ke server sebelum dipakai (via ETag/Last-Modified)
no-store Jangan cache sama sekali (data sensitif — bank, medical)
max-age=N Cache valid N detik
s-maxage=N Cache valid N detik untuk shared cache (CDN), override max-age
immutable Data tidak akan berubah selama hidup cache (cocok untuk hash-named assets)
stale-while-revalidate=N Serve stale response + refresh di background selama N detik

Pola real-world:

// Static product catalog — aman cache lama
res.set("Cache-Control", "public, max-age=3600, s-maxage=86400");

// User profile sendiri — per-user, cache browser saja
res.set("Cache-Control", "private, max-age=60");

// Dashboard real-time — jangan cache
res.set("Cache-Control", "no-store");

// Boleh stale 5 menit saat refresh background
res.set("Cache-Control", "public, max-age=300, stale-while-revalidate=600");

ETag + Conditional Request — Cache Validation

Kadang data bisa di-cache tapi cache-time tidak diketahui. Solusi: ETag (identifier unik dari response). Klien kirim ETag di request berikutnya; kalau belum berubah, server return 304 Not Modified (tanpa body).

import crypto from "crypto";

app.get("/api/articles/:id", (req, res) => {
  const article = getArticle(req.params.id);
  const etag = crypto.createHash("md5").update(JSON.stringify(article)).digest("hex");

  // Klien sudah punya versi ini?
  if (req.headers["if-none-match"] === etag) {
    return res.status(304).end();  // No body, hemat bandwidth
  }

  res.set("ETag", etag);
  res.set("Cache-Control", "private, max-age=0, must-revalidate");
  res.json(article);
});

Browser otomatis kirim If-None-Match: <etag> di request berikutnya. Kalau sama, server hemat compute body + network tidak perlu kirim bytes. Cocok untuk data yang jarang berubah tapi tidak bisa di-cache lama (misal: user profile yang kadang di-edit).

Last-Modified — Alternatif ETag

Mirip ETag tapi pakai timestamp:

app.get("/api/articles/:id", (req, res) => {
  const article = getArticle(req.params.id);
  const lastMod = new Date(article.updated_at).toUTCString();

  if (req.headers["if-modified-since"] === lastMod) {
    return res.status(304).end();
  }

  res.set("Last-Modified", lastMod);
  res.json(article);
});

ETag lebih akurat (granularitas lebih tinggi), Last-Modified lebih mudah (pakai kolom updated_at yang sudah ada).

CDN Caching untuk API

CDN (Cloudflare, Fastly, AWS CloudFront) bisa cache API response di edge — user di Jakarta dapat response dari server CDN di Jakarta, bukan server asli di Singapore.

Syarat CDN cache:

// Response yang CDN-cacheable
res.set("Cache-Control", "public, s-maxage=300");
res.set("Vary", "Accept-Language, Authorization");
res.set("CDN-Cache-Control", "max-age=600");  // override untuk CDN saja (Cloudflare)

Cache Invalidation

"There are only two hard things in Computer Science: cache invalidation and naming things." — Phil Karlton

Strategi umum:

  1. Time-based (TTL) — paling simple; cache expired setelah N detik. OK untuk data yang boleh stale beberapa menit.
  2. Event-based purge — saat data berubah, kirim purge request ke CDN. Cloudflare: POST /zones/{id}/purge_cache. Cepat tapi butuh koordinasi.
  3. Versioned URLapi/v2/products vs api/v1/products. Ganti version = cache baru. Mahal tapi 100% correctness.
  4. Cache key dengan hash konten/assets/app.abc123.js. Berubah = nama baru = cache baru. Ideal untuk static assets.

Anti-Pattern Umum

Cache response dengan Set-Cookie header di CDN — semua user dapat cookie user pertama yang hit. Keamanan breach. Selalu Cache-Control: private untuk response berisi cookie user.

Cache error responses — 500 bisa transient, jangan cache 500 detik. Pakai Cache-Control: no-store untuk status 5xx.

Lupa Vary: Authorization — CDN cache response user A dan kirim ke user B. Gunakan Vary untuk header yang mempengaruhi response.

Checklist

Yang akan kamu pelajari