From harness-claude
Create NestJS microservices with @MessagePattern and @EventPattern. Configure TCP, Redis, RabbitMQ, Kafka, or NATS transport. Supports hybrid apps and RPC exception handling.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:nestjs-microservicesThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Connect services with ClientsModule, @MessagePattern, @EventPattern, and TCP/Redis transport
Connect services with ClientsModule, @MessagePattern, @EventPattern, and TCP/Redis transport
// main.ts
const app = await NestFactory.createMicroservice<MicroserviceOptions>(AppModule, {
transport: Transport.REDIS,
options: { host: 'localhost', port: 6379 },
});
await app.listen();
@Controller()
export class OrdersController {
@MessagePattern({ cmd: 'get_order' }) // request/response
getOrder(@Payload() data: { id: string }): Promise<Order> {
return this.ordersService.findOne(data.id);
}
@EventPattern('order_created') // fire-and-forget
async handleOrderCreated(@Payload() data: OrderCreatedEvent): Promise<void> {
await this.inventoryService.reserve(data.items);
}
}
// register the client in a module
@Module({
imports: [
ClientsModule.register([
{
name: 'ORDERS_SERVICE',
transport: Transport.REDIS,
options: { host: 'localhost', port: 6379 },
},
]),
],
})
// inject and use
@Injectable()
export class ApiGatewayService {
constructor(@InjectClient('ORDERS_SERVICE') private client: ClientProxy) {}
getOrder(id: string): Observable<Order> {
return this.client.send<Order>({ cmd: 'get_order' }, { id });
}
notifyOrderCreated(event: OrderCreatedEvent): Observable<void> {
return this.client.emit('order_created', event);
}
}
const app = await NestFactory.create(AppModule);
app.connectMicroservice<MicroserviceOptions>({
transport: Transport.REDIS,
options: { host: 'localhost', port: 6379 },
});
await app.startAllMicroservices();
await app.listen(3000);
RpcException inside message handlers — it serializes cleanly to the caller.Transport comparison:
send() vs emit(): send() is request/response — it returns an Observable that emits the reply. emit() is fire-and-forget — it returns an Observable that completes when the message is sent (no reply). Always subscribe() to both, or convert to Promise with firstValueFrom().
@Payload() and @Ctx(): Use @Payload() to extract the message payload. Use @Ctx() to get the transport context (e.g., RmqContext for RabbitMQ to manually acknowledge messages).
Manual acknowledgment (RabbitMQ):
@MessagePattern('order_created')
async handle(@Payload() data: OrderCreatedEvent, @Ctx() context: RmqContext) {
const channel = context.getChannelRef();
const message = context.getMessage();
await this.processOrder(data);
channel.ack(message); // only ack after successful processing
}
Serialization: By default, NestJS serializes/deserializes with JSON.stringify/parse. For binary protocols (protobuf, msgpack), configure a custom serializer/deserializer pair.
https://docs.nestjs.com/microservices/basics
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeImplements event-driven patterns in NestJS using EventEmitter2 for in-process pub/sub and CQRS with CommandBus and QueryBus for separating read/write models.
Designs microservices architectures with service boundaries, event-driven communication, data management, and resilience patterns. For decomposing monoliths and building distributed systems.
Provides expert guidance on Nest.js architecture, modules, DI, controllers, guards, interceptors, pipes, and testing with Jest/Supertest.