@hexadrop/command
v2.0.1
Published
Hexagonal architecture utils library
Downloads
1,021
Maintainers
Readme
npm install --save @hexadrop/command
Using bun
bun add @hexadrop/command
What it does
This package is an opinionated utility designed to streamline the creation and dispatching commands in CQRS (Command Query Responsibility Segregation) applications.
It provides a set of abstractions and utilities that allow developers to handle commands in a structured and efficient way. Key features include:
- Command Creation: Simplifies the process of creating new commands.
- Command Dispatching: Provides mechanisms to dispatch commands to their respective handlers.
- Command Handler Decorators: Provides decorators to define command handlers.
How to use
First of all define your commands. A command is a simple class that extends the Command
class and defines
the properties that will be passed to the command handler.
// src/commands/create-user.command.ts
class CreateUserCommand extends Command {
static override COMMAND_NAME = 'user.create';
constructor(
readonly id: string,
readonly name: string,
readonly age: number
) {
super(CreateUserCommand.COMMAND_NAME);
}
}
// src/commands/delete-user.command.ts
class DeleteUserCommand extends Command {
static override COMMAND_NAME = 'user.delete';
constructor(readonly id: string) {
super(CreateUserCommand.COMMAND_NAME);
}
}
Then define your command handlers. A command handler is a simple class that implements the CommandHandler
interface
// src/handlers/create-user.handler.ts
import Either from '@hexadrop/either';
class CreateUserHandler implements CommandHandler<CreateUserCommand> {
constructor(private readonly usersRepository: UsersRepository) {}
async handle(command: CreateUserCommand): Promise<Either<DomainError, void>> {
const { age, id, name } = command;
await this.usersRepository.create({ age, id, name });
return Either.right();
}
}
// src/handlers/delete-user.handler.ts
import Either from '@hexadrop/either';
class DeleteUserHandler implements CommandHandler<DeleteUserCommand> {
constructor(private readonly usersRepository: UsersRepository) {}
async handle(command: DeleteUserCommand): Promise<Either<DomainError, void>> {
const { id } = command;
await this.usersRepository.delete(id);
return Either.right();
}
}
Finally, you can dispatch your commands. To do so you need to create a CommandBus
instance and register your command
handlers.
// src/index.ts
import CommandBus from '@hexadrop/command/bus';
import SyncCommandBus from '@hexadrop/command/bus/sync';
import InMemoryCommandHandlers from '@hexadrop/command/handlers/memory';
import { CreateUserCommand, DeleteUserCommand } from './commands';
import { CreateUserHandler, DeleteUserHandler } from './handlers';
const usersRepository; // Your users repository
const createUserHandler = new CreateUserHandler(usersRepository);
const deleteUserHandler = new DeleteUserHandler(usersRepository);
const handlers = new InMemoryCommandHandlers();
handlers.register(CreateUserCommand, createUserHandler);
handlers.register(DeleteUserCommand, deleteUserHandler);
const commandBus: CommandBus = new SyncCommandBus(handlers);
commandBus.dispatch(new CreateUserCommand('1', 'John', 30));
commandBus.dispatch(new DeleteUserCommand('1'));
Hexadrop Code Quality Standards
Publishing this package we are committing ourselves to the following code quality standards:
- Respect Semantic Versioning: No breaking changes in patch or minor versions
- No surprises in transitive dependencies: Use the bare minimum dependencies needed to meet the purpose
- One specific purpose to meet without having to carry a bunch of unnecessary other utilities
- Tests as documentation and usage examples
- Well documented README showing how to install and use
- License favoring Open Source and collaboration