Rate Limiting — API

Rate Limiting membatasi jumlah request yang bisa dikirim client dalam periode waktu tertentu. Mengapa penting: Mencegah abuse dan DDoS attack Menjaga performa…

Rate limiting membatasi berapa banyak request yang boleh dikirim satu client dalam satu jangka waktu, misalnya 5 request per menit. Bayangin mesin kopi kantor yang memberi tiap karyawan 5 gelas per jam. Gelas keenam ditolak, dan layarnya bilang "coba lagi 12 menit lagi". Batasnya (5), jangka waktunya (1 jam), penolakannya, dan keterangan kapan boleh coba lagi: semuanya ada juga di API.

🧪 Tebakan cepat: batasnya 5 request per menit, dihitung per menit jam dinding (00 sampai 59 detik). Bisakah satu client mengirim 10 request yang semuanya diterima dalam 5 detik? Tebak dulu, jawabannya ada di bagian "Tiga cara menghitung".

Kenapa API butuh batas

Jawaban saat batas terlampaui: 429

Request keenam dalam satu menit dijawab begini:

HTTP/1.1 429 Too Many Requests
Retry-After: 42
RateLimit-Limit: 5
RateLimit-Remaining: 0
RateLimit-Reset: 42
Content-Type: application/json

{"error": "Too many requests, please try again later."}

Tiga cara menghitung

Batasnya sama: 5 request per 60 detik. Cara menghitungnya yang beda.

Coba skenario ini: 5 request di detik ke-55, lalu 5 request lagi di detik ke-60.

Algoritma Detik 55 (5 request) Detik 60 (5 request) Total diterima
Fixed window 5 diterima (menit ke-0) 5 diterima (menit ke-1, penghitung baru) 10 dalam 5 detik
Sliding window 5 diterima 5 ditolak (60 detik terakhir sudah 5) 5
Token bucket 5 diterima, ember kosong 5 ditolak (baru terisi 5/12 token) 5

Jadi bisa: dengan fixed window, 10 request diterima dalam 5 detik, dua kali lipat batasnya. Itu jawaban tebakannya. Ini kelemahan fixed window di perbatasan menit. Sliding window dan token bucket gak punya lubang itu, dengan harga lebih banyak yang harus disimpan.

Menulis limiter sendiri (fixed window)

const WINDOW_MS = 60 * 1000; // 1 menit, dalam milidetik
const LIMIT = 5;
const counters = {}; // "ip:awal menit" -> jumlah request

app.get("/api/data", (req, res) => {
  const now = Date.now();
  const windowStart = Math.floor(now / WINDOW_MS) * WINDOW_MS;
  const key = (req.ip ?? "local") + ":" + windowStart;
  counters[key] = (counters[key] ?? 0) + 1;

  const resetIn = Math.ceil((windowStart + WINDOW_MS - now) / 1000);
  res.set("RateLimit-Limit", String(LIMIT));
  res.set("RateLimit-Remaining", String(Math.max(LIMIT - counters[key], 0)));
  res.set("RateLimit-Reset", String(resetIn));

  if (counters[key] > LIMIT) {
    res.set("Retry-After", String(resetIn));
    return res.status(429).json({ error: "Too many requests, please try again later." });
  }
  res.json({ data: "Hello!" });
});
Request ke- counters[key] Status RateLimit-Remaining
1 1 200 4
5 5 200 0
6 6 429 0

Dengan express-rate-limit

Di aplikasi Express sungguhan, kamu biasanya memakai paket express-rate-limit:

const rateLimit = require("express-rate-limit");

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 menit = 900.000 ms
  limit: 100,               // versi lama menulisnya max: 100
  standardHeaders: "draft-6", // kirim RateLimit-Limit, -Remaining, -Reset
  legacyHeaders: false,       // tanpa X-RateLimit-*
});

app.use("/api/", limiter);

Tester latihan gak punya paket ini, jadi di latihan kamu menulis penghitungnya sendiri seperti contoh sebelumnya.

🤔 Per IP, per user, atau per API key?

⚠️ Jebakan yang sering ketemu

TL;DR: Rate limiting membatasi request per client per jangka waktu. Yang melewati batas dijawab 429 Too Many Requests dengan Retry-After (detik menunggu). RateLimit-Limit, RateLimit-Remaining, dan RateLimit-Reset (sisa detik) ikut di setiap jawaban; nama lamanya X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset. Fixed window paling sederhana tapi bisa meloloskan 2x batas di perbatasan menit; sliding window menghitung 60 detik terakhir; token bucket membolehkan ledakan sebesar ember lalu irama tetap. Di express-rate-limit, windowMs dalam milidetik (15 * 60 * 1000 = 900.000) dan limit (dulu max) jumlah request-nya. Pisahkan penghitung per IP atau per user, dan return setelah 429.

Yang akan kamu pelajari