Di lesson API Gateway kamu sudah kenal gateway sebagai pintu masuk tunggal. Lesson ini membahas lima pola yang membuatnya lebih dari sekadar penerus request: BFF, agregasi paralel, request collapsing, circuit breaker, dan versioned routing. Bayangin kepala pelayan di restoran besar. Tamu anak-anak dapat menu kecil, tamu dewasa menu lengkap. Satu pesanan diambilkan dari tiga dapur sekaligus. Kalau dua puluh meja memesan sup yang sama di menit yang sama, dapur memasak satu panci, bukan dua puluh. Kalau panggangan rusak, dia berhenti mengirim pesanan ke sana dan menawarkan menu lain. Dan pelanggan lama yang masih memesan pakai nomor menu tahun lalu tetap dilayani.
🧪 Tebakan cepat: jam 10.00, 10.000 orang membuka halaman Konser Nusantara dalam 1 detik. Satu panggilan gateway ke service
konserbutuh 30 ms. Dengan request collapsing, berapa kali gateway memanggilkonser: 1, 34, atau 10.000? Tebak dulu, jawabannya ada di bagian "Request collapsing".
Pengingat: tugas dasar gateway
API gateway adalah single entry point yang mengurus hal yang dibutuhkan semua service, di satu tempat: routing ke service yang tepat, autentikasi token, rate limiting, SSL termination (gateway yang membuka koneksi HTTPS dari client, lalu meneruskan request ke service lewat jaringan internal), dan logging. Semua pola di bawah dibangun di atas itu.
Contoh lesson ini satu layar: halaman Konser Nusantara (event 42). Angka model contoh: HP Budi 80 ms bolak-balik dari server, gateway menambah 2 ms, lalu gateway memanggil tiga service: konser (detail konser, 30 ms), order (tiket Budi untuk konser ini, 40 ms), dan rekomendasi (konser serupa, 50 ms).
Backend for Frontend (BFF)
Gateway generik memberi semua client response yang sama. Masalahnya, layar web dan layar HP butuh hal berbeda. Web menampilkan deskripsi, semua kategori tiket, gambar besar, dan 12 rekomendasi. HP cuma butuh nama, tanggal, harga termurah, sisa tiket, thumbnail, dan 3 rekomendasi. Dengan satu response untuk semua, HP mengunduh data yang gak dipakai (over-fetching), atau web harus menembak request tambahan (under-fetching).
BFF artinya tiap jenis client punya gateway (atau lapisan) sendiri yang membentuk response untuk layarnya: GET /web/v2/events/42 dan GET /mobile/v2/events/42. Di Lab, response web 973 byte dan response mobile 306 byte, dari service yang sama. Harganya: ada lebih banyak gateway yang harus dirawat, dan biasanya tiap BFF dipegang tim frontend-nya.
Agregasi paralel
Dengan aggregation pattern, HP cukup mengirim satu request, dan gateway yang memanggil service-service di belakangnya lalu menggabungkan hasilnya jadi satu response. Ketiga panggilan untuk halaman konser gak saling bergantung, jadi gateway bisa memanggilnya bersamaan:
| Gateway memanggil | Kerja service | Total di HP Budi |
|---|---|---|
| berurutan | 30 + 40 + 50 = 120 ms | 80 + 2 + 120 = 202 ms |
paralel (Promise.all) |
yang terlama, 50 ms | 80 + 2 + 50 = 132 ms |
Kalau satu panggilan bergantung pada hasil panggilan lain (seperti "Pesanan saya" di lesson API Gateway), bagian itu tetap berurutan. Pisahkan juga data penting dari yang pelengkap: kalau konser gagal, halaman gak ada artinya, jadi jawab error. Kalau rekomendasi gagal, kirim halaman tanpa rekomendasi (fallback []).
Request collapsing
Saat war tiket, ribuan request identik datang bersamaan: GET /events/42. Tanpa apa-apa, gateway meneruskan semuanya, dan konser dihantam 10.000 panggilan untuk data yang persis sama. Request collapsing (juga disebut single-flight): kalau panggilan untuk key yang sama sedang berjalan, request baru gak memanggil lagi, tapi menunggu hasil panggilan yang sama.
Dengan 10.000 request merata dalam 1.000 ms dan panggilan konser 30 ms, panggilan baru cuma dimulai tiap kali yang sebelumnya selesai: di ms 0, 30, 60, sampai 990. Itu 1.000 ÷ 30 = 33,3, dibulatkan ke atas jadi 34 panggilan, bukan 10.000. Itu jawaban tebakannya. Bedanya dengan cache: collapsing gak menyimpan apa-apa setelah panggilannya selesai. Keduanya sering dipakai bersama.
Circuit breaker di gateway
Misalkan rekomendasi hang: gak menolak, cuma gak menjawab. Tiap request menunggu sampai timeout 1.000 ms, jadi halaman konser butuh 80 + 2 + 1.000 = 1.082 ms, padahal konser dan order sehat. Circuit breaker berhenti memanggil service yang sedang rusak:
| State | Perilaku | Pindah ke |
|---|---|---|
CLOSED |
panggil seperti biasa, hitung kegagalan beruntun | OPEN setelah 5 kegagalan |
OPEN |
jangan panggil, langsung pakai fallback | HALF_OPEN setelah 30 detik |
HALF_OPEN |
coba satu panggilan | CLOSED kalau berhasil, OPEN lagi kalau gagal |
// Gateway TiketNada: halaman konser 42, panggilan paralel + circuit breaker (model contoh)
const RTT = 80, GW = 2, TIMEOUT = 1000; // ms
let mati = false; // rekomendasi hang?
let detik = 0; // jam virtual
const breaker = { state: "CLOSED", gagal: 0, bukaSampai: 0 };
function panggilRekomendasi() {
let percobaan = "";
if (breaker.state === "OPEN") {
if (detik < breaker.bukaSampai) return { ms: 0, catatan: "breaker OPEN, dilewati, fallback []" };
breaker.state = "HALF_OPEN"; // cooldown habis: coba satu panggilan
percobaan = "percobaan half-open: ";
}
if (mati) {
breaker.gagal += 1;
if (breaker.state === "HALF_OPEN" || breaker.gagal >= 5) {
breaker.state = "OPEN";
breaker.bukaSampai = detik + 30;
}
return { ms: TIMEOUT, catatan: `${percobaan}timeout ${TIMEOUT} ms, fallback []` };
}
breaker.state = "CLOSED";
breaker.gagal = 0;
return { ms: 50, catatan: `${percobaan}50 ms` };
}
function kirim() {
detik += 1;
const rek = panggilRekomendasi();
const kerja = Math.max(30, 40, rek.ms); // konser, order, rekomendasi: paralel
console.log(`[${detik} s] ${RTT + GW + kerja} ms, rekomendasi: ${rek.catatan}, breaker ${breaker.state}`);
}
kirim();
mati = true;
for (let i = 0; i < 6; i++) kirim();
detik += 30;
kirim();
Output-nya:
[1 s] 132 ms, rekomendasi: 50 ms, breaker CLOSED
[2 s] 1082 ms, rekomendasi: timeout 1000 ms, fallback [], breaker CLOSED
[3 s] 1082 ms, rekomendasi: timeout 1000 ms, fallback [], breaker CLOSED
[4 s] 1082 ms, rekomendasi: timeout 1000 ms, fallback [], breaker CLOSED
[5 s] 1082 ms, rekomendasi: timeout 1000 ms, fallback [], breaker CLOSED
[6 s] 1082 ms, rekomendasi: timeout 1000 ms, fallback [], breaker OPEN
[7 s] 122 ms, rekomendasi: breaker OPEN, dilewati, fallback [], breaker OPEN
[38 s] 1082 ms, rekomendasi: percobaan half-open: timeout 1000 ms, fallback [], breaker OPEN
Math.max(30, 40, rek.ms): agregasi paralel. Waktu kerja gateway = panggilan yang paling lama.breaker.gagal >= 5: kegagalan kelima beruntun membuka breaker di detik 6, sampai detik 36.- Di detik 7,
rekomendasigak dipanggil sama sekali: 0 ms, fallback[], dan halaman kembali cepat (122 ms). - Di detik 38 cooldown sudah lewat, jadi satu panggilan percobaan dikirim (
HALF_OPEN). Gagal, jadiOPENlagi sampai detik 68.
Retry dengan exponential backoff, bulkhead, dan detail lain dibahas di lesson Resilience Patterns.
Versioned routing
Aplikasi HP yang sudah terpasang gak bisa dipaksa update hari itu juga. Kalau konser mengubah harga dari teks jadi angka, aplikasi lama rusak. Dengan versioned routing, gateway membedakan versi dari path (/v1/..., /v2/...) atau header, dan versi lama tetap mendapat bentuk lamanya:
// GET /mobile/v1/events/42
{ "hargaMulai": "Rp750.000" }
// GET /mobile/v2/events/42
{ "hargaMulai": 750000, "mataUang": "IDR" }
Service cukup punya satu bentuk terbaru, dan gateway atau BFF yang menerjemahkannya ke v1. Versi lama dimatikan setelah hampir gak ada yang memakainya.
🤔 Gateway yang makin gemuk
Setiap pola menambah kerja di gateway. Jaga batasnya: gateway membentuk, menggabungkan, melindungi, dan meneruskan, sedangkan aturan bisnis (harga, kuota, siapa boleh membatalkan) tetap di service. BFF yang mulai menghitung diskon sendiri adalah tanda logika bisnis bocor ke tempat yang salah.
⚠️ Jebakan yang sering ketemu
- Agregasi berurutan padahal gak saling bergantung. 202 ms yang bisa jadi 132 ms.
- Circuit breaker tanpa fallback. Breaker yang OPEN cuma mengubah timeout jadi error cepat. Tentukan dulu apa yang dikirim saat service pelengkap mati.
- Collapsing data pribadi. Hanya request yang hasilnya sama untuk semua orang yang boleh digabung, misalnya detail konser. "Tiket Budi" gak boleh dibagi ke Siti.
- Retry tanpa backoff di gateway. Service yang sedang kesulitan malah dihujani request ulang. Retry pakai jeda yang makin panjang, dan biarkan circuit breaker yang menghentikannya.
TL;DR: API gateway adalah single entry point untuk routing, autentikasi, rate limiting, SSL termination, dan logging; di atasnya ada lima pola. BFF: tiap jenis client (web, mobile) punya gateway yang membentuk response untuk layarnya, sedangkan gateway generik memberi semua client format yang sama (TiketNada: web 973 byte, mobile 306 byte). Agregasi: HP mengirim satu request, gateway memanggil service-nya paralel (202 ms jadi 132 ms), dan bagian pelengkap boleh pakai fallback. Request collapsing: request identik yang datang saat panggilan masih berjalan menunggu hasil yang sama (10.000 request jadi 34 panggilan). Circuit breaker: setelah 5 kegagalan beruntun OPEN selama 30 detik, lalu HALF_OPEN mencoba satu panggilan (1.082 ms jadi 122 ms). Versioned routing: /v1 tetap melayani aplikasi lama.