EventBridge Message Bus Adapter
DRY Castore MessageBus
definition using AWS EventBridge.
📥 Installation
npm install @castore/event-bridge-message-bus-adapter
yarn add @castore/event-bridge-message-bus-adapter
This package has @castore/core
and @aws-sdk/client-eventbridge
(above v3) as peer dependencies, so you will have to install them as well:
npm install @castore/core @aws-sdk/client-eventbridge
yarn add @castore/core @aws-sdk/client-eventbridge
👩💻 Usage
import { EventBridgeClient } from '@aws-sdk/client-eventbridge';
import { EventBridgeMessageBusAdapter } from '@castore/event-bridge-message-bus-adapter';
const eventBridgeClient = new EventBridgeClient({});
const messageBusAdapter = new EventBridgeMessageBusAdapter({
eventBusName: 'my-event-bus-name',
eventBridgeClient,
});
const messageBusAdapter = new EventBridgeMessageBusAdapter({
eventBusName: () => process.env.MY_EVENT_BUS_NAME,
eventBridgeClient,
});
const appMessageBus = new NotificationMessageBus({
...
messageBusAdapter
})
This will directly plug your MessageBus to EventBridge 🙌
🤔 How it works
When publishing a message, its eventStoreId
is used as the message source
and its event type
is used as detail-type
(except for AggregateExistsMessageBus
for which a constant is used). The whole message is passed to the detail
property.
{
"source": "POKEMONS",
"detail-type": "__AGGREGATE_EXISTS__",
"detail": {
"eventStoreId": "POKEMONS",
"aggregateId": "123",
},
...
}
{
"source": "POKEMONS",
"detail-type": "POKEMON_APPEARED",
"detail": {
"eventStoreId": "POKEMONS",
"event": {
"aggregateId": "123",
"version": 1,
"type": "POKEMON_APPEARED",
"timestamp": ...
...
},
},
...
}
{
"source": "POKEMONS",
"detail-type": "POKEMON_APPEARED",
"detail": {
"eventStoreId": "POKEMONS",
"event": {
"aggregateId": "123",
...
},
"aggregate": { ... }
},
...
}
If the replay
option is set to true
when publishing a notification or state-carrying message, the "detail-type"
will be set to "__REPLAYED__"
. This makes sure that any subscription to replayed events is opt-in:
{
"source": "POKEMONS",
"detail-type": "__REPLAYED__",
"detail": {
"eventStoreId": "POKEMONS",
"event": {
"aggregateId": "123",
"type": "POKEMON_APPEARED",
...
},
},
...
}
On the listeners side, you can use the EventBridgeMessageBusMessage
TS type to type your argument:
import type { EventBridgeMessageBusMessage } from '@castore/event-bridge-message-bus-adapter';
const listener = async (
message: EventBridgeMessageBusMessage<typeof appMessageBus>,
) => {
const { eventStoreId, event } = message.detail;
};
You can provide event store ids and event types if you listener only listens to specific event types:
import type { EventBridgeMessageBusMessage } from '@castore/event-bridge-message-bus-adapter';
const listener = async (
message: EventBridgeMessageBusMessage<
typeof appMessageBus,
'POKEMONS',
'POKEMON_APPEARED'
>,
) => {
const { eventStoreId, event } = message.detail;
};
🔑 IAM
The publishMessage
method requires the events:PutEvents
IAM permission on the provided event bus.