Belajar Microservices - API Gateway + Integrasi Frontend (Studi Kasus Utuh)
Episode 10 of 28

Belajar Microservices - API Gateway + Integrasi Frontend (Studi Kasus Utuh)

Menyatukan semua layanan ke dalam api-gateway (BFF) dengan routing, validasi JWT, rate-limit, CORS, dan agregasi respons, lalu membangun web-app React yang hanya berbicara ke gateway — dan membuktikannya dengan satu alur end-to-end yang utuh

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

Pendahuluan

Tujuh layanan sudah bangun di episode 4-9, tapi masing-masing masih jadi pulau. Saatnya menjembatani mereka: api-gateway (dengan peran BFF) akan menjadi satu pintu masuk untuk seluruh client, dan web-app React menjadi wajah pertama yang hanya mengenal gateway — bukan layanan internal.

Mengapa episode ini disebut studi kasus utuh? Karena inilah pertama kalinya satu alur bisnis lengkap mengalir melewati semua layanan dalam satu request-chain yang nyata: dari browser sampai email keluar. Kalian akan merasakan langsung perbedaan dari monolith: log menyebar, cache bekerja, event mengalir — dan gateway jadi titik yang mengatur semuanya.

Peran api-gateway (BFF)

Routing per Service

Satu pintu masuk, URL yang bersih untuk client:

Routing gateway
/api/auth/*       → auth-service       :3001
/api/products/*   → product-service    :3002
/api/cart/*       → cart-service       :3003
/api/orders/*     → order-service      :3004
/api/payments/*   → payment-service    :3005

Client tidak pernah tahu bahwa ada enam layanan berbeda di belakangnya. Ini menyembunyikan kompleksitas internal dan memberi kebebasan menata ulang arsitektur tanpa mengubah API publik.

Middleware Gateway

Gateway menempelkan empat lapisan sebelum meneruskan request:

  1. JWT validation — verifikasi access token sekali di depan. Request valid masuk; token rusak ditolak dengan 401 sebelum menyentuh layanan.
  2. Rate limiting — batasi request per IP/user (misal 100 req/menit per IP di endpoint publik; lebih ketat di login).
  3. CORS — izinkan asal yang dikenal (https://tokokita.id) — bukan wildcard.
  4. Request ID — injeksi x-request-id agar semua service bisa melacak satu request di log (fase 5, episode 20).
api-gateway dengan Elysia (rute + auth checking)
import { Elysia } from 'elysia'
 
const app = new Elysia()
  .derive(({ headers }) => {
    return { requestId: headers['x-request-id'] ?? randomUUID() }
  })
  .onBeforeHandle(async ({ path, headers, set }) => {
    if (isPublicRoute(path)) return
    const token = headers.authorization?.replace('Bearer ', '')
    if (!token) {
      set.status = 401
      return { error: 'unauthenticated' }
    }
    const payload = await verifyAccessToken(token)
    if (!payload) {
      set.status = 401
      return { error: 'invalid token' }
    }
    return { user: payload }
  })
  // lalu forward via fetch ke service masing-masing (service discovery ringan)

Di episode 11 kita akan membangun service discovery dan pattern forward yang benar; di episode 17, ingress akan menggantikan sebagian peran ini di Kubernetes.

Response Aggregation

Beberapa halaman butuh data dari banyak layanan sekaligus. Contoh: halaman Detail Produk yang menampilkan produk + rating. Rating ada di layanan lain? Bisa dengan agregasi di gateway:

Agregasi detail produk
async function productDetail(id: string) {
  const [product, rating] = await Promise.all([
    fetchInternal(`http://product-service:3002/products/${id}`),
    fetchInternal(`http://rating-service:3006/products/${id}/rating`),
  ])
  return { ...product, rating }
}

Promise.all menjalankan panggilan paralel sehingga total watu halaman memakai maksimum dari keduanya, bukan penjumlahan.

Caution

Jangan jadikan gateway ratu tunggal yang mengeksekusi seluruh logika bisnis — itu baru monolith kedua. Gateway hanya berbicara presentasi: routing, auth boundary, agregasi ringan. Logika bisnis (validasi stok, kalkulasi total, state machine) tetap di layanan pemilik domain. Saat agregasi mulai berat & spesifik per client, pecahlah menjadi BFF per client (bff-web, bff-mobile).

web-app (React)

Frontend dibangun dengan React + Vite di folder apps/web-app. Halaman yang dibutuhkan:

  • Home / Katalog — grid produk dari GET /api/products.
  • Detail produk — plus tombol add-to-cart.
  • Cart — lihat, ubah qty, checkout.
  • Checkout — form alamat + ringkasan order.
  • Order history — GET /api/orders/me.
  • Login / Register.

Prinsipnya: web-app hanya memanggil api-gateway. Tidak ada fetch langsung ke product-service:3002 dari browser. Semua auth header ditaruh oleh client helper:

apps/web-app/src/lib/api.ts
const API = '/api'
 
export async function api<T>(path: string, init: RequestInit = {}) {
  const res = await fetch(`${API}${path}`, {
    ...init,
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${localStorage.getItem('access_token')}`,
      ...init.headers,
    },
  })
  return (await res.json()) as T
}

Alur End-to-End Pertama

100%

Langkah verifikasi manual di browser:

  1. Register user baru → cek email selamat datang di Mailpit (localhost:8025).
  2. Login → simpan access token.
  3. Browse katalog produk.
  4. Add to cart → lihat cart.
  5. Checkout → buat order (idempotency key otomatis dari client).
  6. Pay → mock gateway langsung payment.succeeded.
  7. Cek order berstatus PAID.
  8. Cek email konfirmasi pembayaran di Mailpit.

Verifikasi Semua Service Hidup

Pastikan seluruh stack jalan di Compose:

Cek semua layanan
docker compose -f infra/compose.yaml ps --format '{{.Name}} {{.Status}}'
curl -s localhost:4000/api/health

Gateway mengekspos /api/health yang melakukan ping ke tiap service di belakangnya dan melaporkan status aggregat.

Penutup

Episode 10 menyatukan tokokita:

  • api-gateway (BFF): routing per service, JWT validation, rate-limit, CORS, request-id, agregasi respons.
  • web-app React: halaman katalog → detail → cart → checkout → order history, hanya bicara ke gateway.
  • Agregasi memakai Promise.all untuk paralel; gateway tidak boleh jadi monolith kedua.
  • Alur end-to-end pertama berhasil: register → email, login → browse → cart → checkout → bayar → PAID → email bukti.

Di episode 11 selanjutnya, kita akan masuk ke komunikasi sinkron: REST & gRPC — menghindari sinkron-chain berantai, memutuskan kapan REST vs gRPC, otentikasi service-to-service, serta retry, timeout, dan circuit breaker untuk downstream. Sampai jumpa di episode 11!

Belajar Microservices - API Gateway + Integrasi Frontend (Studi Kasus Utuh) | Belajar Microservices