All Projects → snatalenko → node-cqrs

snatalenko / node-cqrs

Licence: MIT License
CQRS backbone with event sourcing for Node.js

Programming Languages

javascript
184084 projects - #8 most used programming language
Handlebars
879 projects

Projects that are alternatives of or similar to node-cqrs

Extreme
Elixir Adapter for EventStore
Stars: ✭ 110 (+74.6%)
Mutual labels:  cqrs, eventstore, event-sourcing
workflow
Functional CQRS Eventsourcing Engine
Stars: ✭ 22 (-65.08%)
Mutual labels:  cqrs, eventstore, event-sourcing
Bifrost
This is the stable release of Dolittle till its out of alpha->beta stages
Stars: ✭ 111 (+76.19%)
Mutual labels:  cqrs, eventstore, event-sourcing
Event Sourcing Castanha
An Event Sourcing service template with DDD, TDD and SOLID. It has High Cohesion and Loose Coupling, it's a good start for your next Microservice application.
Stars: ✭ 68 (+7.94%)
Mutual labels:  cqrs, eventstore, event-sourcing
iam-ddd-cqrs-es-nestjs
Identity and Access Management
Stars: ✭ 34 (-46.03%)
Mutual labels:  cqrs, eventstore, event-sourcing
Nestjs Cqrs Starter
NestJS CQRS Microservices Starter Project
Stars: ✭ 80 (+26.98%)
Mutual labels:  cqrs, eventstore, event-sourcing
Cqrs
cqrs framework in go
Stars: ✭ 179 (+184.13%)
Mutual labels:  cqrs, eventstore, event-sourcing
Eventstore
The stream database optimised for event sourcing
Stars: ✭ 4,395 (+6876.19%)
Mutual labels:  cqrs, eventstore, event-sourcing
Learning.EventStore
A framework for CQRS, Eventsourcing, and messaging that uses Redis pub/sub for messaging and offers event persistence in Redis, SQL Server, or PostgreSQL.
Stars: ✭ 58 (-7.94%)
Mutual labels:  cqrs, eventstore, event-sourcing
nestjs-boilerplate-microservice
Nestjs Microservice boilerplate: apply DDD, CQRS, and Event Sourcing within an event driven architecture
Stars: ✭ 270 (+328.57%)
Mutual labels:  cqrs, eventstore, saga
Ultimate Backend
Multi tenant SaaS starter kit with cqrs graphql microservice architecture, apollo federation, event source and authentication
Stars: ✭ 978 (+1452.38%)
Mutual labels:  cqrs, eventstore, event-sourcing
node-event-storage
An optimized event store for node.js
Stars: ✭ 29 (-53.97%)
Mutual labels:  cqrs, eventstore, event-sourcing
Eventstore
Event store using PostgreSQL for persistence
Stars: ✭ 729 (+1057.14%)
Mutual labels:  cqrs, eventstore, event-sourcing
Commanded
Use Commanded to build Elixir CQRS/ES applications
Stars: ✭ 1,280 (+1931.75%)
Mutual labels:  cqrs, eventstore, event-sourcing
Equinoxproject
Full ASP.NET Core 5 application with DDD, CQRS and Event Sourcing concepts
Stars: ✭ 5,120 (+8026.98%)
Mutual labels:  cqrs, eventstore, event-sourcing
Eventflow.example
DDD+CQRS+Event-sourcing examples using EventFlow following CQRS-ES architecture. It is configured with RabbitMQ, MongoDB(Snapshot store), PostgreSQL(Read store), EventStore(GES). It's targeted to .Net Core 2.2 and include docker compose file.
Stars: ✭ 131 (+107.94%)
Mutual labels:  cqrs, eventstore, event-sourcing
Eventually Rs
Event Sourcing for Rust
Stars: ✭ 277 (+339.68%)
Mutual labels:  cqrs, eventstore, event-sourcing
wolkenkit-eventstore
wolkenkit-eventstore is an open-source eventstore for Node.js that is used by wolkenkit.
Stars: ✭ 79 (+25.4%)
Mutual labels:  cqrs, eventstore, event-sourcing
es-emergency-call
Struggling with CQRS, A+ES, DDD? We can help you!
Stars: ✭ 26 (-58.73%)
Mutual labels:  cqrs, event-sourcing, aggregate
eventuous
Minimalistic Event Sourcing library for .NET
Stars: ✭ 236 (+274.6%)
Mutual labels:  cqrs, eventstore, event-sourcing

node-cqrs

NPM Version Build Status Coverage Status NPM Downloads

Overview

The package provides building blocks for making a CQRS-ES application. It was inspired by Lokad.CQRS, but not tied to a specific storage implementation or infrastructure. It favors ES6 classes and dependency injection, so any components can be modified or replaced with your own implementations without hacks to the package codebase.

Documentation at node-cqrs.org

Your app is expected to operate with loosely typed commands and events that match the following interface:

declare interface IMessage {
    type: string,

    aggregateId?: string|number,
    aggregateVersion?: number,

    sagaId?: string|number,
    sagaVersion?: number,

    payload?: any,
    context?: any
}

Domain business logic should be placed in Aggregate, Saga and Projection classes:

  • Aggregates handle commands and emit events
  • Sagas handle events and enqueue commands
  • Projections listen to events and update views

Message delivery is being handled by the following services (in order of appearance):

  • Command Bus delivers commands to command handlers
  • Aggregate Command Handler restores an aggregate state, executes a command
  • Event Store persists events and deliver them to event handlers (saga event handlers, projections or any other custom services)
  • Saga Event Handler restores saga state and applies event

From a high level, this is how the command/event flow looks like:

Overview

Getting Started

You can find sample code of a User domain in the /examples folder.

Your App → Command → Aggregate

Describe an aggregate that handles a command:

const { AbstractAggregate } = require('node-cqrs');

class UserAggregate extends AbstractAggregate {
  static get handles() {
    return ['createUser'];
  }
  
  createUser(commandPayload) {
    // ...
  }
}

Then register aggregate in the DI container. All the wiring can be done manually, without a DI container (you can find it in samples), but with container it’s just easier:

const { ContainerBuilder, InMemoryEventStorage } = require('node-cqrs');

const builder = new ContainerBuilder();
builder.register(InMemoryEventStorage).as('storage');
builder.registerAggregate(UserAggregate);

const container = builder.container();

Then send a command:

const userAggregateId = undefined;
const payload = {
  username: 'john',
  password: 'test'
};

container.commandBus.send('createUser', userAggregateId, { payload });

Behind the scene, an AggregateCommandHandler will catch the command, try to load an aggregate event stream and project it to aggregate state, then it will pass the command payload to the createUser handler we’ve defined earlier.

The createUser implementation can look like this:

createUser(commandPayload) {
  const { username, password } = commandPayload;

  this.emit('userCreated', {
    username,
    passwordHash: md5Hash(password)
  });
}  

Once the above method is executed, the emitted userCreated event will be persisted and delivered to event handlers (sagas, projections or any other custom event receptors).

Aggregate → Event → Projection → View

Now it’s time to work on a read model. We’ll need a projection that will handle our events. Projection must implement 2 methods: subscribe(eventStore) and project(event) . To make it easier, you can extend an AbstractProjection:

const { AbstractProjection } = require('node-cqrs');

class UsersProjection extends AbstractProjection {
  static get handles() {
    return ['userCreated'];
  }
  
  userCreated(event) {
    // ...
  }
}

By default, projection uses async InMemoryView for inner view, but we’ll use Map to make it more familiar:

class UsersProjection extends AbstractProjection {
  get view() {
    return this._view || (this._view = new Map());
  }

  // ...
}

With Map view, our event handler can look this way:

class UsersProjection extends AbstractProjection {
  // ...

  userCreated(event) {
    this.view.set(event.aggregateId, {
      username: event.payload.username
    });
  }
}

Once the projection is ready, it can be registered in the DI container:

builder.registerProjection(UsersProjection, 'users');

And accessed from anywhere in your app:

container.users
// Map { 1 => { username: 'John' } }

Contribution

License

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].