Microservices dengan NestJS di 2026: Arsitektur, gRPC, dan Pertanyaan Wawancara

Panduan praktis arsitektur NestJS microservices dengan gRPC: service boundaries, transport layers, streaming patterns, dan pertanyaan wawancara umum untuk 2026.

Arsitektur NestJS Microservices dengan gRPC

Arsitektur microservices NestJS telah menjadi pendekatan standar untuk membangun backend Node.js terdistribusi pada tahun 2026. Dengan transport layer yang ditingkatkan pada NestJS 12, dukungan gRPC first-class, exception filters untuk RPC calls, dan propagasi trace ID otomatis, framework ini menyediakan semua yang diperlukan untuk memecah monolith menjadi services yang memiliki batas jelas tanpa mengorbankan developer experience.

gRPC vs REST untuk internal services

gRPC menggunakan Protocol Buffers dan HTTP/2, memberikan serialisasi hingga 10x lebih cepat dan native bidirectional streaming dibandingkan JSON over REST. Untuk komunikasi service-to-service di dalam cluster, gRPC mengurangi latency dan memastikan kontrak yang ketat melalui file .proto. REST tetap menjadi pilihan yang lebih baik untuk public-facing APIs yang diakses oleh browser dan pihak ketiga.

Arsitektur Transport Layer NestJS Microservices

Package @nestjs/microservices menggantikan HTTP controllers dengan message-oriented handlers. Alih-alih routing berdasarkan URL path, setiap handler merespons message pattern, sebuah string atau object key yang mengidentifikasi operasi. Abstraksi ini berarti logic handler yang sama bekerja di TCP, Redis, NATS, Kafka, RabbitMQ, atau gRPC tanpa perubahan kode.

NestJS 11 memperkenalkan method unwrap() pada semua transporters, memberikan akses langsung ke underlying client instance. Ini menyelesaikan pain point lama: memeriksa connection state, tuning keepalive intervals, atau mengakses fitur spesifik broker yang tidak diekspos oleh abstraksi NestJS. NestJS 12 membangun di atas ini dengan pre-request hooks, memungkinkan handlers mengeksekusi logic kustom segera sebelum invokasi untuk cross-cutting concerns seperti auth checks atau metrics.

Dua pola komunikasi menggerakkan NestJS microservices:

  • Request-response (@MessagePattern): client mengirim message dan menunggu balasan. Cocok untuk synchronous queries seperti mengambil user profile atau memvalidasi token.
  • Event-based (@EventPattern): client mengirimkan event dan melanjutkan, tidak ada response yang diharapkan. Ideal untuk audit logs, notifikasi, atau memicu downstream workflows.
orders.controller.tstypescript
import { Controller } from '@nestjs/common';
import { MessagePattern, EventPattern, Payload } from '@nestjs/microservices';
import { OrdersService } from './orders.service';
import { CreateOrderDto } from './dto/create-order.dto';

@Controller()
export class OrdersController {
  constructor(private readonly ordersService: OrdersService) {}

  // Request-response: caller waits for the created order
  @MessagePattern('order.create')
  async createOrder(@Payload() data: CreateOrderDto) {
    return this.ordersService.create(data);
  }

  // Event-based: fire and forget, no response returned
  @EventPattern('order.shipped')
  async handleOrderShipped(@Payload() data: { orderId: string }) {
    await this.ordersService.markAsShipped(data.orderId);
  }
}

Handler @MessagePattern secara otomatis melakukan serialisasi return value dan mengirimkannya kembali melalui transport. Handler @EventPattern tidak mengembalikan apa pun: NestJS membuang return value apapun.

Deprecation EventPattern di NestJS 12

Mulai NestJS 12, transports TCP, Redis, NATS, MQTT, dan RabbitMQ mencatat deprecation warning ketika handler @EventPattern membalas ke ClientProxy#send(). Perilaku ini akan berubah di versi major berikutnya, selaras dengan pendekatan Kafka yang sudah ada. Migrasikan event handlers ke semantik fire-and-forget yang sebenarnya atau beralih ke @MessagePattern untuk flow request-response.

Konfigurasi gRPC sebagai Transport Microservice NestJS

Integrasi gRPC di NestJS dimulai dengan file .proto yang mendefinisikan service contract. Protocol Buffers memastikan type safety di level wire: baik client maupun server harus setuju dengan exact shape dari setiap message sebelum satu byte pun berjalan di network.

proto/users.protoprotobuf
syntax = "proto3";

package users;

service UsersService {
  rpc FindOne (UserById) returns (User);
  rpc FindMany (UserFilter) returns (stream User);
}

message UserById {
  string id = 1;
}

message UserFilter {
  string role = 1;
  int32 limit = 2;
}

message User {
  string id = 1;
  string email = 2;
  string name = 3;
  string role = 4;
}

Di sisi server, aplikasi NestJS mem-bootstrap gRPC microservice dengan menunjuk ke proto file dan binding network address:

main.tstypescript
import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { join } from 'path';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.createMicroservice<MicroserviceOptions>(
    AppModule,
    {
      transport: Transport.GRPC,
      options: {
        package: 'users',
        protoPath: join(__dirname, 'proto/users.proto'),
        url: '0.0.0.0:5000',
      },
    },
  );
  await app.listen();
}
bootstrap();

Controller menggunakan @GrpcMethod sebagai pengganti @MessagePattern. Decorator menerima nama service dan nama RPC method sebagai argumen, mapping langsung ke definisi proto:

users.controller.tstypescript
import { Controller } from '@nestjs/common';
import { GrpcMethod } from '@nestjs/microservices';
import { UsersService } from './users.service';

@Controller()
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @GrpcMethod('UsersService', 'FindOne')
  async findOne(data: { id: string }) {
    return this.usersService.findById(data.id);
  }
}

NestJS menangani proto loading, serialisasi, dan HTTP/2 connection management secara otomatis. Method controller menerima plain TypeScript objects, tidak perlu decoding proto manual.

Pola Streaming gRPC dalam NestJS

Server streaming cocok untuk skenario di mana satu request menghasilkan multiple results seiring waktu: real-time price feeds, paginated database cursors, atau progress updates selama long-running task. Handler mengembalikan RxJS Observable, dan NestJS men-stream setiap emitted value ke client sebagai message gRPC terpisah:

users.controller.ts (server streaming)typescript
import { Observable, from } from 'rxjs';
import { map } from 'rxjs/operators';
import { GrpcMethod } from '@nestjs/microservices';

@GrpcMethod('UsersService', 'FindMany')
findMany(data: { role: string; limit: number }): Observable<any> {
  // Stream users matching the filter one by one
  const users$ = from(this.usersService.findByRole(data.role, data.limit));
  return users$.pipe(
    map((user) => ({
      id: user.id,
      email: user.email,
      name: user.name,
      role: user.role,
    })),
  );
}

Bidirectional streaming menggunakan @GrpcStreamCall(). Baik client maupun server mengirim independent streams, berguna untuk sistem chat, collaborative editing, atau multiplexed telemetry ingestion. Handler menerima instance grpc.ServerDuplexStream dan mengelola read/write cycle secara manual.

NestJS 12 menambahkan backpressure handling: request streams sekarang pause saat replies mereka menunggu untuk ditulis. Ini mencegah buffer overflow ketika slow consumer tidak dapat mengikuti fast producer.

Penanganan error streaming

Observable yang crash di dalam gRPC stream mengakhiri seluruh call dengan status CANCELLED. Bungkus stream logic dalam operator catchError dan emit gRPC-appropriate error metadata. Unhandled stream errors adalah penyebab nomor satu dari mysterious connection drops di production NestJS gRPC services.

gRPC Exception Filters di NestJS 12

NestJS 12 memperkenalkan dedicated exception handling untuk gRPC, mencerminkan pola HTTP exception filter yang familiar. Status-specific exception classes memungkinkan handlers mengembalikan gRPC-native error codes alih-alih generic failures:

grpc-exception.filter.tstypescript
import { Catch, RpcExceptionFilter, ArgumentsHost } from '@nestjs/common';
import { Observable, throwError } from 'rxjs';
import { RpcException } from '@nestjs/microservices';
import { status } from '@grpc/grpc-js';

@Catch(RpcException)
export class GrpcExceptionFilter implements RpcExceptionFilter<RpcException> {
  catch(exception: RpcException, host: ArgumentsHost): Observable<any> {
    const error = exception.getError() as { code?: number; message?: string };
    return throwError(() => ({
      code: error.code ?? status.INTERNAL,
      message: error.message ?? 'Internal error',
    }));
  }
}

Terapkan filter secara global atau per-controller untuk memastikan respons error yang konsisten di semua gRPC endpoints. Dikombinasikan dengan class RpcException yang sudah ada, ini membawa paritas error handling antara HTTP dan gRPC transports.

Aplikasi Hybrid: HTTP dan gRPC pada Service yang Sama

Banyak real-world NestJS services membutuhkan baik public REST API maupun internal gRPC endpoints. Pola hybrid application menghubungkan multiple transports ke single NestJS instance:

main.ts (hybrid application)typescript
import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions, Transport } from '@nestjs/microservices';
import { join } from 'path';
import { AppModule } from './app.module';

async function bootstrap() {
  // HTTP server on port 3000
  const app = await NestFactory.create(AppModule);

  // gRPC microservice on port 5000
  app.connectMicroservice<MicroserviceOptions>({
    transport: Transport.GRPC,
    options: {
      package: 'users',
      protoPath: join(__dirname, 'proto/users.proto'),
      url: '0.0.0.0:5000',
    },
  });

  await app.startAllMicroservices();
  await app.listen(3000);
}
bootstrap();

Pendekatan ini menghindari deployment services terpisah ketika single bounded context membutuhkan baik external maupun internal interfaces. Container dependency injection yang sama, guards, interceptors, dan pipes berlaku untuk kedua transports, mengurangi duplikasi dan menjaga perilaku tetap konsisten.

Siap menguasai wawancara Node.js / NestJS Anda?

Berlatih dengan simulator interaktif, flashcards, dan tes teknis kami.

Pola Regexp Kafka di NestJS 12

NestJS 12 memungkinkan @MessagePattern() dan @EventPattern() menerima regular expressions untuk Kafka topics. Satu handler sekarang dapat subscribe ke multiple topics secara dinamis:

multi-topic.controller.tstypescript
import { Controller } from '@nestjs/common';
import { EventPattern, Payload, Ctx, KafkaContext } from '@nestjs/microservices';

@Controller()
export class AnalyticsController {
  // Matches analytics.pageview, analytics.click, analytics.purchase, etc.
  @EventPattern(/^analytics..*/)
  handleAnalyticsEvent(
    @Payload() data: Record<string, unknown>,
    @Ctx() context: KafkaContext,
  ) {
    const topic = context.getTopic();
    console.log(`Received event on ${topic}`, data);
  }
}

Ini mengurangi boilerplate ketika multiple topics berbagi handler logic yang sama. Perhatikan bahwa validasi pattern key di NestJS 12 memastikan maksimum 256 karakter: patterns yang lebih panjang gagal secara diam-diam dan tidak cocok dengan handler manapun.

Migrasi NATS v3 di NestJS 12

NestJS 12 mengganti NATS client dengan package resmi @nats-io/transport-node. Ini adalah breaking change: deserializers sekarang menerima full message object alih-alih raw payload.

typescript
// Before (NestJS 11)
deserialize(value: any): any {
  return JSON.parse(value);
}

// After (NestJS 12): read payload via msg.json()
deserialize(msg: any): any {
  return msg.json();
}

Update semua custom NATS deserializers saat migrasi ke NestJS 12. Client baru membawa improved performance dan alignment dengan official NATS ecosystem.

Batasan Service dan Domain-Driven Design dengan NestJS

Memecah monolith menjadi microservices tanpa batas yang jelas menciptakan distributed monolith, yang terburuk dari kedua arsitektur. Setiap NestJS microservice harus memiliki single bounded context: database sendiri, domain models sendiri, dan deployment lifecycle sendiri.

Panduan praktis untuk menggambar batasan service di NestJS:

  • Satu modul NestJS per aggregate root. Jika Order dan OrderLine selalu berubah bersama, mereka termasuk dalam service yang sama. Jika User dan Order berubah secara independen, mereka layak memiliki services terpisah.
  • Async events untuk cross-domain side effects. Ketika order ditempatkan, emit event order.created via Kafka atau RabbitMQ. Inventory service bereaksi tanpa order service mengetahui keberadaannya.
  • Shared proto packages untuk contracts. Simpan file .proto di shared repository. Baik producer maupun consumer menghasilkan types dari source of truth yang sama, sehingga drift menjadi CI failure, bukan production incident.

Opsi microservice NestJS 12 dari DI container membuat konfigurasi service dapat diuji. Alih-alih hardcoding broker URLs di main.ts, inject ConfigService dan swap connection strings per environment tanpa rebuilding.

Pola Reliability: Timeouts, Retries, dan Circuit Breakers

Internal gRPC calls tanpa deadlines mengubah satu slow dependency menjadi system-wide outage. Setiap ClientProxy.send() call harus menyertakan timeout:

orders.service.tstypescript
import { Inject, Injectable } from '@nestjs/common';
import { ClientGrpc } from '@nestjs/microservices';
import { firstValueFrom, timeout, retry } from 'rxjs';

@Injectable()
export class OrdersService {
  private usersService: any;

  constructor(@Inject('USERS_PACKAGE') private client: ClientGrpc) {}

  onModuleInit() {
    this.usersService = this.client.getService('UsersService');
  }

  async getOrderWithUser(orderId: string, userId: string) {
    // 3-second deadline, 2 retries with exponential backoff
    const user = await firstValueFrom(
      this.usersService.findOne({ id: userId }).pipe(
        timeout(3000),
        retry({ count: 2, delay: (err, retryCount) => {
          const jitter = Math.random() * 100;
          return new Promise(r => setTimeout(r, 1000 * retryCount + jitter));
        }}),
      ),
    );
    return { orderId, user };
  }
}

Retries hanya boleh diterapkan pada idempotent operations. Retry call CreateOrder berisiko duplicate orders. Retry query FindOne aman karena tidak memiliki side effects.

Untuk fungsionalitas circuit breaker, library opossum terintegrasi dengan baik dengan NestJS. Bungkus ClientGrpc calls dalam circuit breaker yang terbuka setelah N consecutive failures dan tertutup setelah configurable reset timeout.

Propagasi trace NestJS 12

NestJS 12 melanjutkan automatic trace ID propagation yang diperkenalkan di NestJS 11 di seluruh Kafka, RabbitMQ, dan gRPC transports. Dikombinasikan dengan OpenTelemetry, ini memungkinkan full distributed tracing tanpa custom interceptors.

Pertanyaan Wawancara NestJS Microservices

Technical interviews untuk posisi backend semakin banyak menguji pengetahuan microservices bersamaan dengan framework-specific patterns. Pertanyaan-pertanyaan ini mencakup konsep yang paling sering ditanyakan dalam wawancara NestJS-focused.

Apa perbedaan antara @MessagePattern dan @EventPattern?

@MessagePattern mengimplementasikan request-response: client mengirim message dan blocks sampai menerima reply. @EventPattern mengimplementasikan fire-and-forget: client mengirim event dan melanjutkan eksekusi segera. Di bawah hood, @MessagePattern mengembalikan result handler melalui transport, sementara @EventPattern membuang return values. Perhatikan bahwa NestJS 12 mendeprecate replying dari @EventPattern handlers pada sebagian besar transports.

Bagaimana NestJS memuat dan mengikat file .proto untuk gRPC?

NestJS menggunakan package @grpc/proto-loader untuk mengurai file .proto saat startup dan menghasilkan service descriptors. Konfigurasi GrpcOptions menentukan proto path dan package name. Controllers yang dianotasi dengan @GrpcMethod('ServiceName', 'MethodName') dicocokkan dengan parsed descriptors. Jika method yang dideklarasikan di proto tidak memiliki matching handler, NestJS throws saat bootstrap.

Kapan gRPC harus menggantikan REST antar microservices?

gRPC cocok untuk internal service-to-service calls di mana type safety, performa, dan streaming penting. Protocol Buffers menghasilkan payloads yang lebih kecil dan serialisasi yang lebih cepat daripada JSON. HTTP/2 multiplexing mengurangi connection overhead. REST tetap lebih disukai untuk public APIs, browser clients, dan third-party integrations di mana human readability dan broad tooling support lebih penting daripada raw performance.

Bagaimana pola hybrid application bekerja?

NestFactory.create() mem-boot HTTP server. Memanggil app.connectMicroservice() menghubungkan additional transports (gRPC, Kafka, Redis, atau transporter yang didukung lainnya) ke instance aplikasi NestJS yang sama. Semua transports berbagi module tree, DI container, dan middleware pipeline yang sama. app.startAllMicroservices() memulai semua connected transporters, dan app.listen() memulai HTTP layer.

Pola reliability apa yang mencegah cascading failures?

Tiga pola yang paling penting: timeouts (setiap RPC call membutuhkan deadline), retries dengan jitter (hanya untuk idempotent operations, dengan exponential backoff plus random jitter untuk menghindari thundering herds), dan circuit breakers (terbuka setelah N failures, half-open setelah cooldown, tertutup begitu health checks lulus). Integrasi RxJS NestJS membuat timeouts dan retries dapat dikomposisikan melalui pipe operators.

Apa yang berubah untuk microservices di NestJS 12?

NestJS 12 menambahkan gRPC exception filters untuk status-specific error handling, Kafka regexp patterns untuk multi-topic handlers, dukungan NATS v3 dengan package client baru, pre-request hooks untuk microservice handlers, dan improved gRPC stream backpressure. Deprecation warning @EventPattern menandakan perubahan perilaku di masa depan di mana event handlers tidak lagi akan membalas ke send() calls.

Untuk latihan lebih mendalam tentang pola arsitektur NestJS, modul NestJS modules and dependency injection mencakup fundamental DI yang mendasari komposisi microservice. Modul middleware and interceptors membahas cross-cutting concerns yang dibagikan di seluruh transports. Panduan NestJS and GraphQL mencakup alternatif untuk gRPC untuk typed service APIs.

Mulai berlatih!

Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.

Sources

Poin Penting NestJS Microservices di 2026

  • Abstraksi transport NestJS 12 memungkinkan services beralih antara TCP, gRPC, Kafka, dan NATS tanpa menulis ulang handler logic: decorator @MessagePattern dan @EventPattern bekerja identik di semua transports
  • gRPC dengan Protocol Buffers memastikan kontrak yang ketat antar services melalui file .proto, menangkap integration errors saat compile time bukan di production
  • Hybrid applications menggabungkan HTTP dan gRPC pada instance NestJS yang sama, menghilangkan kebutuhan untuk men-deploy services terpisah untuk public dan internal interfaces
  • Server streaming via RxJS Observables memungkinkan real-time data feeds tanpa kompleksitas WebSocket, dengan NestJS 12 menambahkan backpressure handling untuk slow consumers
  • Setiap internal RPC call membutuhkan deadline, retries hanya berlaku untuk idempotent operations, dan circuit breakers mencegah satu slow service dari cascading menjadi full outage
  • Batasan service mengikuti domain-driven design: satu bounded context per service, async events untuk komunikasi cross-domain, shared proto packages untuk contract enforcement

Mulai berlatih!

Uji pengetahuan Anda dengan simulator wawancara dan tes teknis kami.

Tantangan harian

Bisakah kamu menemukan bug di Node.js / NestJS?

Satu potongan kode nyata, satu bug tersembunyi, satu percobaan per hari. Tanpa akun untuk mencoba.

Anthony Fillion-Maillet

Ditulis oleh

Anthony Fillion-Maillet

Pendiri SharpSkill

Developer fullstack selama lebih dari 10 tahun. Ia menjalankan SharpSkill dan bertanggung jawab atas semua yang diterbitkan di sini.

Diperbarui 22 Oktober 2026

Tag

#nestjs
#microservices
#grpc
#nodejs
#typescript
#architecture

Bagikan

Artikel terkait