npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

node-cqrs-framework

v2.0.1

Published

A CQRS implementation in nodeJS with promises.

Downloads

22

Readme

node-cqrs-framework

CircleCI CodeFactor Coverage Status

node-cqrs-framework is a node.js framework that helps you to implement microservices and scalability for cqrs architectures over rabbitmq service discovery.

Advantages

  • Think better! Think KISS!
  • Configuration-driven oriented framework.
  • Only one monolithic project in your github.
  • Only one monolithic project to maintain.
  • Start only the services you want with configuration file.
  • Agnostics commands and queries, they just had to be promises.
  • Tests are dissociate from the notion of CQRS.
  • Deploy and scale your microservices like you want.
  • Automatic services discovery! Thanks rabbitmq.

Installation

$ npm i -S node-cqrs-framework

Description

Beware, you need a rabbitmq running in localhost for all those examples.

Server

The server is the main program, he needs to be start at first. Because the project is configuration-driven, you only need those lines of code to start all selected microservices in a row.

Glob patterns

This syntax will load all pomises in this dirpath and attach a 1:1 queue for execute the promise. And attach two 1:N queues (on for success event, and the second for error event).

server.use(path.resolve(__dirname, '../test/data/commands/*.js'))

Simple server

const path = require('path')

const Server = require('node-cqrs-framework').Server
const server = new Server()

// all options from servicebus (see npm)
const options = {
  host: 'localhost',
  port: 5672,
  user: 'guest',
  pass: 'guest',
  timeout: 2000,
  heartbeat: 10
}

server
  .use(path.resolve(__dirname, '../test/data/commands/*.js'))
  .use(path.resolve(__dirname, '../test/data/queries/*.js'))
  .start(options)

server.on('error', error => {
  console.log('server error')
  console.log(error)
})

server.on('ready', () => {
  console.log('server connected')
})

Service

A service is the base element of the CQRS, it's like a microservice or a task. The application result of a service will automaticaly:

  • Send an event on the bus in case of success
  • Send an event on the bus in case of error

You will never have to use this class, Command and Query extend it.

Command

  • "A result" is either a successful application of the command, or an exception.
  • Because it extends Service, success event or error event will be automaticaly send on the bus.

How to create a Command ?

Step 1
You need to create a file who contains "Command" in his name.
path/you/want/BasicNopeCommand.js

Step 2
You need to module.exports a promise.

const Promise = require('bluebird')

const handler = function () {
  return new Promise((resolve, reject) => {
    resolve()
  })
}

module.exports = handler

Query

From the framework point of view a query is the same as a command, but because of queries roles in the CQRS architecture, this time data will be return.

  • "A result" is either data, or an exception
  • Because it extends Service, success event or error event will be automaticaly send on the bus

How to create a Query ?

Step 1
You need to create a file who contains "Query" in his name.
path/you/want/BasicNopeQuery.js

Step 2
You need to module.exports a promise.

const Promise = require('bluebird')

const handler = function () {
  return new Promise((resolve, reject) => {
    resolve({data: true})
  })
}

module.exports = handler

Now it's time to start the server

Classic start:

$ node examples/server.js

But, you can run the server in debug mode.

$ DEBUG=cqrs:* node examples/server.js

Client

It's time to learn how to link all those services and events together, let's me introduce the Client object.

Definitions

A client could be wherever you need it to be, even on another server, or behind a hapiJS/Express server, or why not in another CQRS Server.
You will have three patterns to use the server events bus.

Sender/Receiver pattern

The Send / Receive object pair uses a direct exchange inside of RabbitMQ

Publisher/Subscriber pattern

The Publish / Subscribe object pair uses a fanout exchange inside of RabbitMQ, allowing you to have as many subscribers as you need. Think of pub/sub as an event that gets broadcast to anyone that cares, or no one at all if no one is listening.

Request/Response pattern

The request/response pair uses a "topic" exchange. With a request/response setup, you can send a request for information and respond to it.

Send a Query

  • When the server start and load your handlers, receivers are created in the server.
  • Sender client is a classic fire and forget on the bus. In return you will have only a result who informs you if the command or the query has been executed succesfully or not.

Create a file client-sender.js, and and this code in:

const Client = require('node-cqrs-framework').Client
const client = new Client()

// all options from servicebus (see npm)
const options = {
  host: 'localhost',
  port: 5672,
  user: 'guest',
  pass: 'guest',
  timeout: 2000,
  heartbeat: 10
}

client
  .subscribe('BasicNopeQuery.Success', (result) => {
    console.log('success', result)
    client.close()
  })
  .subscribe('BasicNopeQuery.Error', (result) => {
    console.log('error', result)
    client.close()
  })
  .start(options)

client.on('error', error => {
  console.log('client error')
  console.log(error)
})

client.on('ready', () => {
  console.log('client connected')
  client.send('BasicNopeQuery', {message: 'This is a query'})
})

Nota

  • The pattern BasicNopeQuery.* will receive Error and Success event for one specific Query.
  • The pattern *.Error will receive Errors for all Commands and Queries.

Now it's time to start the client-send

Classic start:

$ node examples/client-sender.js

But, you can run the client in debug mode.

$ DEBUG=cqrs:* node examples/client-sender.js

Result will be:

{ type: 'Query',
  name: 'BasicNopeQuery',
  event: 'BasicNopeQuery.Success',
  params: { message: 'This is a query' },
  exectime: 1004,
  result: { data: true } }

Request a Query

  • When the client start a specific queue is created on the server.
  • The server will have in the data received an automatic header to help him answering the client who called.
  • Events succes or error are also published.

Create a file client-request.js, and and this code in:

const Client = require('node-cqrs-framework').Client
const client = new Client()
client
  .subscribe('BasicNopeQuery.Success', (result) => {
    console.log('success', result)
    client.close()
  })
  .subscribe('BasicNopeQuery.Error', (result) => {
    console.log('error', result)
    client.close()
  })
  .start()

client.on('error', error => {
  console.log('client error')
  console.log(error)
})

client.on('ready', () => {
  console.log('client connected')
  client.request('BasicNopeQuery', {message: 'This is a query'}, (data) => {
    console.log('result', data)
  })
})

Result from the success event will be:

success { type: 'Query',
  name: 'BasicNopeQuery',
  event: 'BasicNopeQuery.Success',
  params:
   { message: 'This is a query',
     __headers:
      { 'x-client-id': 'Client.Response.38057d6b-bd49-4b4b-9727-35146c43789a',
        'x-request-id': 'cb0d0e12-8f8c-4267-a20f-fb05c653aba6' } },
  exectime: 1001,
  result: { data: true } }

Result from the response callback will be:

result { type: 'Query',
  name: 'BasicNopeQuery',
  event: 'BasicNopeQuery.Success',
  params: { message: 'This is a query' },
  exectime: 1001,
  result: { data: true } }