Skip to main content
BlogDevOps

Pola API Gateway dengan NestJS: Routing, Auth, dan Rate Limiting dalam Produksi

Cara mengimplementasikan API gateway di NestJS microservices — mencakup routing permintaan, agregasi autentikasi, rate limiting, dan trade-off antara membangun vs membeli.

Matthews Wong

Software Engineer

Juni 202511 menit baca
DevOps

API gateway adalah titik masuk tunggal untuk semua permintaan klien ke backend microservices Anda. Alih-alih klien mengetahui tentang sepuluh endpoint layanan yang berbeda, mereka berbicara ke satu gateway yang merutekan permintaan, menerapkan autentikasi, menerapkan batas laju, dan mengagregasi respons. Dalam arsitektur microservices NestJS, pola gateway sangat penting untuk menjaga batas layanan yang bersih sambil menyajikan API terpadu ke klien front-end.

Apa yang Sebenarnya Dilakukan API Gateway

API gateway berfungsi sebagai reverse proxy cerdas. Tanggung jawabnya: (1) Routing permintaan — mencocokkan jalur HTTP masuk ke microservice downstream yang sesuai; (2) Autentikasi dan otorisasi — memvalidasi JWT atau kunci API sebelum permintaan mencapai layanan; (3) Rate limiting — menerapkan kuota per klien atau per endpoint; (4) Transformasi permintaan/respons — mengadaptasi format payload antara kontrak klien dan layanan; (5) Circuit breaking — berhenti mengirim permintaan ke layanan yang gagal; (6) Agregasi respons — menggabungkan respons dari beberapa layanan menjadi satu payload untuk klien.

Membangun Gateway dengan NestJS

Di NestJS, gateway dapat berupa aplikasi khusus yang bertindak sebagai proxy HTTP. Gunakan @nestjs/axios untuk meneruskan permintaan ke layanan downstream, implementasikan Guards untuk autentikasi di tingkat gateway, dan gunakan Interceptors untuk rate limiting dan transformasi respons. Gateway berkomunikasi dengan layanan melalui gRPC atau HTTP.

API Gateway Architecture (NestJS)

  ┌────────────────────────────────────────────────────┐
  │              Clients                               │
  │  Browser │ Mobile App │ Partner API │ CLI          │
  └──────────────────┬─────────────────────────────────┘
                     │ HTTPS (REST / GraphQL)
                     ▼
  ┌────────────────────────────────────────────────────┐
  │           API Gateway (NestJS)                     │
  │                                                    │
  │  [AuthGuard] → JWT validate → inject X-User-Id    │
  │  [RateLimitInterceptor] → Redis token bucket       │
  │  [TracingInterceptor] → inject X-Request-ID        │
  │  [CircuitBreakerInterceptor] → fail fast           │
  │                                                    │
  │  Route Table:                                      │
  │  /api/orders/*   → OrderService  (gRPC :50051)    │
  │  /api/invoices/* → InvoiceService (gRPC :50052)   │
  │  /api/reports/*  → ReportService (HTTP :3003)     │
  └──────────┬────────────────┬───────────────────────┘
             │                │
      ┌──────▼──────┐  ┌──────▼──────┐
      │  Order      │  │  Invoice    │
      │  Service    │  │  Service    │
      │  (NestJS)   │  │  (NestJS)   │
      └─────────────┘  └─────────────┘

  BFF Extension: /api/dashboard → parallel calls to
  UserService + OrderService + NotificationService → merged response

Tips dari pengerjaan front-end untuk aplikasi bergaya ERP: implementasikan request tracing di lapisan gateway dengan menyuntikkan header X-Request-ID ke setiap permintaan yang diteruskan. Log ID ini di gateway dan setiap layanan downstream. Saat men-debug masalah produksi, Anda dapat merekonstruksi perjalanan permintaan lengkap di seluruh layanan dengan mencari satu ID tersebut di log Anda.

Autentikasi di Gateway

Memusatkan autentikasi di gateway adalah salah satu manfaat terbesar dari pola ini. Alih-alih setiap microservice mengimplementasikan validasi JWT secara independen, gateway memvalidasi token dan meneruskan klaim yang didekode downstream sebagai header (X-User-Id, X-User-Roles). Layanan downstream mempercayai header ini tanpa memvalidasi ulang JWT — mereka hanya perlu memverifikasi permintaan berasal dari gateway (gunakan mTLS atau rahasia internal bersama).

// gateway-auth.guard.ts
@Injectable()
export class GatewayAuthGuard implements CanActivate {
  constructor(private jwt: JwtService) {}

  canActivate(ctx: ExecutionContext): boolean {
    const req = ctx.switchToHttp().getRequest();
    const token = req.headers.authorization?.replace('Bearer ', '');
    if (!token) throw new UnauthorizedException();

    const payload = this.jwt.verify(token);
    // Downstream services trust these headers — never re-validate JWT
    req.headers['x-user-id'] = payload.sub;
    req.headers['x-user-roles'] = payload.roles.join(',');
    req.headers['x-request-id'] = randomUUID(); // inject trace ID
    return true;
  }
}

// dashboard.controller.ts — BFF aggregation
@Controller('dashboard')
export class DashboardController {
  @Get('overview')
  async getOverview(@Headers('x-user-id') userId: string) {
    // Parallel calls — total latency = max(latencies), not sum
    const [profile, orders, notifications] = await Promise.all([
      this.userService.getProfile(userId),
      this.orderService.getRecent(userId, { limit: 5 }),
      this.notificationService.getUnread(userId),
    ]);
    return { profile, orders, notifications };
  }
}

Strategi Rate Limiting

Rate limiting melindungi layanan Anda dari penyalahgunaan dan memastikan penggunaan yang adil. Implementasikan rate limiting di gateway menggunakan algoritma token bucket atau sliding window yang didukung oleh Redis — sehingga batas dibagikan di beberapa instansi gateway. Di NestJS, paket @nestjs/throttler menangani ini dengan dukungan Redis melalui ThrottlerStorageRedisService.

Memusatkan semua lalu lintas melalui gateway berarti itu harus menjadi komponen Anda yang paling andal. Gateway yang down membawa seluruh permukaan API Anda bersamanya. Jalankan beberapa instansi gateway di belakang load balancer. Implementasikan pemeriksaan kesehatan di gateway dan circuit breaker pada panggilan layanan downstream. Monitor latensi dan tingkat kesalahan gateway sebagai SLO utama Anda.

Bangun vs Beli: NestJS vs Kong vs AWS API Gateway

Untuk tim yang sudah berinvestasi di NestJS, membangun gateway di NestJS memberikan kontrol penuh dan menggunakan kembali pola yang ada. Tetapi produk gateway yang dibuat khusus seperti Kong, Traefik, atau AWS API Gateway menangani rate limiting, auth, routing, caching, dan analitik di luar kotak. Gunakan gateway yang dibuat khusus ketika: Anda berada di lingkungan polyglot; Anda membutuhkan fitur enterprise.

Agregasi Respons (Pola BFF)

Pola Backend-for-Frontend (BFF) memperluas gateway dengan menambahkan agregasi respons — gateway memanggil beberapa layanan secara paralel dan menggabungkan hasilnya menjadi satu respons untuk klien. Misalnya, halaman dashboard yang membutuhkan profil pengguna, pesanan terbaru, dan jumlah notifikasi dapat mendapatkan ketiganya dalam satu panggilan API. Di NestJS, implementasikan ini dengan Promise.all() untuk panggilan layanan paralel.

Daftar Periksa Produksi untuk API Gateway

Sebelum ditayangkan: implementasikan endpoint pemeriksaan kesehatan di semua layanan downstream dan konfigurasikan gateway untuk memeriksanya; atur batas timeout pada semua permintaan yang di-proxy; tambahkan circuit breaker dengan respons fallback yang ditentukan; aktifkan distributed tracing dengan propagasi request ID; deploy beberapa instansi gateway dan uji failover.

Sumber & Bacaan Lebih Lanjut

FAQ

Pertanyaan Umum

Jawaban singkat untuk pertanyaan yang paling sering diajukan pembaca tentang topik ini.

Mengapa autentikasi dipusatkan di API gateway daripada di setiap microservice?

Memusatkan autentikasi di gateway berarti hanya satu layanan yang memvalidasi JWT atau kunci API — lalu meneruskan klaim yang telah didekode ke downstream sebagai header tepercaya seperti X-User-Id dan X-User-Roles. Layanan downstream tidak perlu memvalidasi ulang token, cukup memverifikasi bahwa permintaan berasal dari gateway menggunakan mTLS atau rahasia internal bersama. Pendekatan ini menghilangkan duplikasi logika autentikasi setiap kali microservice baru ditambahkan.

Bagaimana cara mencegah API gateway menjadi titik kegagalan tunggal?

Jalankan beberapa instansi gateway di belakang load balancer sehingga satu instansi yang down tidak membawa seluruh permukaan API bersamanya. Implementasikan pemeriksaan kesehatan pada gateway dan circuit breaker pada panggilan layanan downstream, agar gateway gagal secara graceful dengan respons cache atau pesan error yang bermakna. Memantau latensi P99 dan tingkat kesalahan gateway sebagai SLO utama membantu mendeteksi masalah sebelum meluas.

Pendekatan rate limiting apa yang didukung NestJS untuk gateway multi-instansi?

Batas laju harus dibagikan di semua instansi gateway agar efektif, sehingga implementasinya perlu didukung Redis, bukan memori dalam proses. Di NestJS, paket @nestjs/throttler mendukung ini melalui ThrottlerStorageRedisService dengan algoritma token bucket atau sliding window. Strategi umum meliputi batas per-IP untuk endpoint yang tidak terautentikasi dan batas per-pengguna untuk panggilan API yang terautentikasi.

Kapan sebaiknya membangun gateway di NestJS dibandingkan menggunakan Kong, Traefik, atau AWS API Gateway?

Bangun di NestJS ketika tim Anda sudah terbiasa dengan NestJS, kebutuhan sudah terdefinisi dengan baik dan tidak akan berkembang menjadi kompleks, serta ingin menghindari biaya lisensi. Pilih gateway yang dibuat khusus seperti Kong, Traefik, atau AWS API Gateway di lingkungan polyglot atau ketika Anda membutuhkan fitur enterprise seperti alur OAuth2, manajemen kunci API, atau dasbor analitik tanpa harus membangunnya sendiri.

Apa itu pola BFF dan bagaimana cara mengurangi kompleksitas front-end?

Pola Backend-for-Frontend (BFF) memperluas gateway dengan agregasi respons — gateway memanggil beberapa layanan downstream secara paralel dan menggabungkan hasilnya menjadi satu respons. Misalnya, halaman dashboard yang membutuhkan profil pengguna, pesanan terbaru, dan jumlah notifikasi mendapatkan ketiganya dalam satu panggilan API alih-alih tiga permintaan berurutan dari sisi klien. Di NestJS, ini diimplementasikan menggunakan Promise.all() untuk panggilan layanan paralel sebelum hasil digabungkan dan dikembalikan.