Error: Events must implement StorableEvent interface
Closed this issue · 5 comments
Event is not published.
Implementation:
Event
import { StorableEvent } from 'event-sourcing-nestjs';
export class AccountCreatedEvent extends StorableEvent {
eventAggregate: 'account';
eventVersion: 1;
constructor(public readonly id: string, public readonly name: string) {
super();
}
}
Event Emitter
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { Logger } from '@nestjs/common';
import { StoreEventBus } from 'event-sourcing-nestjs';
import { CreateAccountCommand } from '../impl/create-account.command';
import { AccountCreatedEvent } from 'src/account/events/impl/account-created.event';
@CommandHandler(CreateAccountCommand)
export class CreateAccountHandler
implements ICommandHandler<CreateAccountCommand> {
constructor(private readonly eventBus: StoreEventBus) {}
async execute(command: CreateAccountCommand): Promise<string> {
Logger.log('Async CreateUserHandler');
const { name } = command;
const id = '12345';
this.eventBus.publish(new AccountCreatedEvent(id, name));
return id;
}
}
Event Handler
import { IEventHandler, EventsHandler } from '@nestjs/cqrs';
import { Logger } from '@nestjs/common';
import { AccountCreatedEvent } from '../impl/account-created.event';
@EventsHandler(AccountCreatedEvent)
export class UserCreatedHandler implements IEventHandler<AccountCreatedEvent> {
handle(event: AccountCreatedEvent): void {
Logger.log(event, 'AccountCreatedEvent');
}
}
Expected behavior:
Display emitted event log
### Current behavior:
Error: Events must implement StorableEvent interface
at StoreEventBus.publish (/Users/adrian/Projects/Yaydoo/connect/yaydoo-connect-api/node_modules/event-sourcing-nestjs/dist/store-event-bus.js:25:19)
at CreateAccountHandler.execute (/Users/adrian/Projects/Yaydoo/connect/yaydoo-connect-api/dist/account/commands/handlers/create-account.handler.js:26:23)
at CommandBus.execute (/Users/adrian/Projects/Yaydoo/connect/yaydoo-connect-api/node_modules/@nestjs/cqrs/dist/command-bus.js:42:28)
at AccountsService.createAccount (/Users/adrian/Projects/Yaydoo/connect/yaydoo-connect-api/dist/account/services/account.service.js:23:31)
at AccountController.createAccount (/Users/adrian/Projects/Yaydoo/connect/yaydoo-connect-api/dist/account/controllers/account.controller.js:24:37)
at /Users/adrian/Projects/Yaydoo/connect/yaydoo-connect-api/node_modules/@nestjs/core/router/router-execution-context.js:37:29
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async /Users/adrian/Projects/Yaydoo/connect/yaydoo-connect-api/node_modules/@nestjs/core/router/router-execution-context.js:45:28
at async /Users/adrian/Projects/Yaydoo/connect/yaydoo-connect-api/node_modules/@nestjs/core/router/router-proxy.js:8:17
Environment:
Node version: v13.12.0
Yarn version: v1.22.4
Typescript version: 3.7.4
package.json
{
"version": "0.0.1",
"private": true,
"license": "UNLICENSED",
"scripts": {
"prebuild": "rimraf dist",
"build": "nest build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json"
},
"dependencies": {
"@nestjs/common": "^7.0.0",
"@nestjs/core": "^7.0.0",
"@nestjs/cqrs": "^7.0.0",
"@nestjs/platform-express": "^7.0.0",
"@nestjs/swagger": "^4.5.10",
"class-validator": "^0.12.2",
"dotenv": "^8.2.0",
"event-sourcing-nestjs": "^1.1.3",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^6.5.4"
},
"devDependencies": {
"@nestjs/cli": "^7.0.0",
"@nestjs/schematics": "^7.0.0",
"@nestjs/testing": "^7.0.0",
"@types/express": "^4.17.3",
"@types/jest": "25.2.3",
"@types/node": "^13.9.1",
"@types/supertest": "^2.0.8",
"@typescript-eslint/eslint-plugin": "3.0.2",
"@typescript-eslint/parser": "3.0.2",
"eslint": "7.1.0",
"eslint-config-prettier": "^6.10.0",
"eslint-plugin-import": "^2.20.1",
"jest": "26.0.1",
"prettier": "^1.19.1",
"supertest": "^4.0.2",
"ts-jest": "26.1.0",
"ts-loader": "^6.2.1",
"ts-node": "^8.6.2",
"tsconfig-paths": "^3.9.0",
"typescript": "^3.7.4"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".spec.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}
This is the code that checks and throws that exception:
publish<T extends IEvent>(event: T): void {
const storableEvent = (event as any) as StorableEvent;
if (
storableEvent.id === undefined ||
storableEvent.eventAggregate === undefined ||
storableEvent.eventVersion === undefined
) {
throw new Error('Events must implement StorableEvent interface');
}
...
Can you log the event before publishing it? Are any of these fields undefined?
Log added:
publish(event) {
const storableEvent = event;
console.log({ storableEvent }) // <------
if (storableEvent.id === undefined ||
storableEvent.eventAggregate === undefined ||
storableEvent.eventVersion === undefined) {
throw new Error('Events must implement StorableEvent interface');
}
this.eventStore
.storeEvent(storableEvent)
.then(() => this.eventBus.publish(event))
.catch(err => {
throw err;
});
}
This is the result:
{
storableEvent: AccountCreatedEvent {
eventName: 'AccountCreatedEvent',
id: '12345',
name: 'Por Cobrar'
}
}
Isn't getting values from class attributes
export class AccountCreatedEvent extends StorableEvent {
eventAggregate: 'account';
eventVersion: 1;
constructor(public readonly id: string, public readonly name: string) {
super();
}
}
Looks like eventAggregate is undefined, thats why the Store Event Bus is throwing the exception.
eventAggregate y eventVersion are undefined, but I initialized them as attributes in the class, is there something I'm doing wrong?
export class AccountCreatedEvent extends StorableEvent {
eventAggregate: 'account'; <----
eventVersion: 1; <----
constructor(public readonly id: string, public readonly name: string) {
super();
}
}
Sorry, my bad, it was a syntax error, I used : instead of = to assign the value.
Do you have a channel where I can ask you questions regarding the implementation, I am just getting experience in Event Sourcing and CQRS, this is the first project I have to lead with these approaches.