Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
40 prioritized NestJS best practices across architecture, DI, security, performance, testing, and microservices.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
rules/arch-use-events.md
1---2title: Use Event-Driven Architecture for Decoupling3impact: MEDIUM-HIGH4impactDescription: Enables async processing and modularity5tags: architecture, events, decoupling6---78## Use Event-Driven Architecture for Decoupling910Use `@nestjs/event-emitter` for intra-service events and message brokers for inter-service communication. Events allow modules to react to changes without direct dependencies, improving modularity and enabling async processing.1112**Incorrect (direct service coupling):**1314```typescript15// Direct service coupling16@Injectable()17export class OrdersService {18constructor(19private inventoryService: InventoryService,20private emailService: EmailService,21private analyticsService: AnalyticsService,22private notificationService: NotificationService,23private loyaltyService: LoyaltyService,24) {}2526async createOrder(dto: CreateOrderDto): Promise<Order> {27const order = await this.repo.save(dto);2829// Tight coupling - OrdersService knows about all consumers30await this.inventoryService.reserve(order.items);31await this.emailService.sendConfirmation(order);32await this.analyticsService.track('order_created', order);33await this.notificationService.push(order.userId, 'Order placed');34await this.loyaltyService.addPoints(order.userId, order.total);3536// Adding new behavior requires modifying this service37return order;38}39}40```4142**Correct (event-driven decoupling):**4344```typescript45// Use EventEmitter for decoupling46import { EventEmitter2 } from '@nestjs/event-emitter';4748// Define event49export class OrderCreatedEvent {50constructor(51public readonly orderId: string,52public readonly userId: string,53public readonly items: OrderItem[],54public readonly total: number,55) {}56}5758// Service emits events59@Injectable()60export class OrdersService {61constructor(62private eventEmitter: EventEmitter2,63private repo: Repository<Order>,64) {}6566async createOrder(dto: CreateOrderDto): Promise<Order> {67const order = await this.repo.save(dto);6869// Emit event - no knowledge of consumers70this.eventEmitter.emit(71'order.created',72new OrderCreatedEvent(order.id, order.userId, order.items, order.total),73);7475return order;76}77}7879// Listeners in separate modules80@Injectable()81export class InventoryListener {82@OnEvent('order.created')83async handleOrderCreated(event: OrderCreatedEvent): Promise<void> {84await this.inventoryService.reserve(event.items);85}86}8788@Injectable()89export class EmailListener {90@OnEvent('order.created')91async handleOrderCreated(event: OrderCreatedEvent): Promise<void> {92await this.emailService.sendConfirmation(event.orderId);93}94}9596@Injectable()97export class AnalyticsListener {98@OnEvent('order.created')99async handleOrderCreated(event: OrderCreatedEvent): Promise<void> {100await this.analyticsService.track('order_created', {101orderId: event.orderId,102total: event.total,103});104}105}106```107108Reference: [NestJS Events](https://docs.nestjs.com/techniques/events)109