Command Bus
The Command Bus is a central piece of DomusJS, enabling you to dispatch commands (intentions to change system state) through a clean, decoupled pipeline.
✅ Separates the sender from the handler.
✅ Supports CQRS (Command Query Responsibility Segregation).
✅ Allows adding middleware (logging, validation, transactions) transparently.
What is the Command Bus?
Section titled “What is the Command Bus?”Without a command bus, your code would directly call service methods, tightly coupling layers.
With the command bus:
- You dispatch a command.
- The bus finds the registered handler.
- The handler executes the command logic.
Example:
const result = await commandBus.dispatch(new RegisterUserCommand(email, password));
✅ The sender doesn’t need to know the implementation details.
Command Bus Setup
Section titled “Command Bus Setup”To use the Command Bus, you need to:
✅ Ensure the CommandBus implementation has been initialized (by default, InMemoryCommandBus
).
✅ Register each Command and its associated CommandHandler.
ℹ️ Note:
TheCommandBus
should have been initialized earlier by callingregisterDomusCore()
.
You can then safely resolve it from the container usingcontainer.resolve()
.
Example Use Case: Registering a User
Section titled “Example Use Case: Registering a User”Step 1: Define the Command
Section titled “Step 1: Define the Command”import { Command } from '@domusjs/core';
export class RegisterUserCommand implements Command { static TYPE = 'REGISTER_USER'; readonly type = RegisterUserCommand.TYPE;
constructor( public readonly email: string, public readonly password: string ) {}}
Step 2: Create the Command Handler
Section titled “Step 2: Create the Command Handler”import { CommandHandler } from '@domusjs/core';import { RegisterUserCommand } from './register-user.command';
export class RegisterUserHandler implements CommandHandler<RegisterUserCommand> { async execute(command: RegisterUserCommand): Promise<void> { // Business logic: validate, create user, emit events }}
Step 3: Register and Dispatch
Section titled “Step 3: Register and Dispatch”DomusJS provides the helper function registerCommandHandler
to register the command handler.
import { container } from 'tsyringe';import { CommandBus } from '@domusjs/core';import { registerCommandHandler } from '@domusjs/infrastructure';import { RegisterUserCommand } from './register-user.command';import { RegisterUserHandler } from './register-user.handler';
const commandBus = container.resolve<CommandBus>('CommandBus');
registerCommandHandler(commandBus, RegisterUserCommand, RegisterUserHandler);
commandBus.dispatch(new RegisterUserCommand('john@example.com', 'secret123'));
✅ The controller only talks to the bus — no need to know the handler.
✅ You can extend functionality (middleware, tracing) without touching the app logic.
Core Interfaces
Section titled “Core Interfaces”DomusJS defines a minimal set of interfaces:
Command
Section titled “Command”export interface Command { readonly type: string;}
CommandHandler
Section titled “CommandHandler”export interface CommandHandler<C extends Command, R = void> { execute(command: C): Promise<R>;}
CommandBus
Section titled “CommandBus”export interface CommandBus { dispatch<C extends Command, R = void>(command: C): Promise<R>; register<C extends Command, R = void>(commandClass: { TYPE: string }, handler: CommandHandler<C, R>): void;}
✅ You can build your own CommandBus by following this interface.
Advanced: Distributed Command Bus
Section titled “Advanced: Distributed Command Bus”In production systems where services are distributed or deployed as independent processes, it’s often necessary to dispatch commands across process boundaries. DomusJS allows full flexibility in this area by enabling you to implement your own distributed CommandBus.
Examples of distributed patterns:
- gRPC-based CommandBus — Send commands over the network using Protocol Buffers
- Message Queue CommandBus — Dispatch commands via RabbitMQ, Redis, or similar
- Hybrid architecture — Some commands locally, others remotely based on routing rules
🔧 Example: gRPC CommandBus
Section titled “🔧 Example: gRPC CommandBus”A distributed CommandBus over gRPC might:
- Serialize a command into a Protobuf message
- Send it to a remote service over the network
- Deserialize and dispatch to the appropriate handler on the remote side
This pattern is particularly useful for:
- Microservices that need to communicate across service boundaries
- Bounded contexts that operate as independent processes
- Multi-tenant systems where commands route to different instances