Open
Description
You know how much I love this lib… ❤
From the Docs:
order.addEvent('OTHER_EVENT', (...args) => {
console.log(args);
});
// Or add an EventHandler instance
order.addEvent(new OrderCreatedEvent());
order.dispatchEvent('ORDER_HAS_BEGUN');
// dispatch with args
order.dispatchEvent('OTHER_EVENT', { info: 'custom_args' });
// OR call all added events
await order.dispatchAll();
My understanding
- Order is the Aggregate Root
- I want to add the event "OrderCreatedEvent" in a method within the domain
- Later, in a use-case, I might decide to dispatch the event
Complexity
Dispatching the event requires some infrastructure: My Event Bus.
I don't want to add this in the domain layer – bad practice.
What I think I want, is:
- Add the event in the domain layer (with custom args!)
- Dispatch the event in the use case
Problem
The docs describe this round the opposite way, no?
Things I've tried
1. Custom Constructor to EventHandler
order.addEvent(new OrderItemAdded({ newItem }));
– Great, but I still can't dispatch without importing my Event Bus.
2. Custom Parameter
class Order extends AggregateRoot {
function addItem(eventHandler? EventHandler<Order>) {
...do work
if (eventHandler) this.addEvent(eventHandler)
}
}
- Great, but I cannot pass additional args of "newItem"
API I think we need
In domain layer
order.addEvent('ORDER_ITEM_ADDED', { newItem });
– I don't care how it's dispatched here. So I don't care about a "handler".
In UseCase
export class AddItemUseCase extends UseCase {
constructor(deps: {
orderItemAddedHandler: EventHandler<Order>
})
execute() {
...
order.addItem(...)
order.dispatch('ORDER_ITEM_ADDED', this.deps.orderItemAddedHandler)
}
}
– I'm not creating the handler here, I'm just passing it and saying "use this to dispatch the event, thanks!"
And finally, in infra:
export class OrderItemAddedHander extends EventHandler<Order> {
constructor(deps: {
eventBus: EventBus
})
dispatch(order: Order, args) {
this.deps.eventBus.dispatch({
custom: {
shape: {
order,
item: args.newItem
}
}
})
}
}
and
export const addOrderItemUseCase = new AddItemUseCase({
orderItemAddedHandler: new OrderItemAddedHander()
})
– All the definitions of things without any understanding or logic as to when this all gets called.
Bonus!
Strict typing of the event args would be 👌🏻
Something like:
interface CustomArgs {
newItem: …
}
EventHandler<Order, CustomArgs>
Metadata
Metadata
Assignees
Labels
No labels