Full stack CQRS, DDD, Event Sourcing framework for Node.js

Overview

Build Status npm version GitHub license

CQRS DDD Event Sourcing React Redux

reSolve is a full stack functional JavaScript framework.

πŸš€ Getting Started

Installation

Make sure you have NodeJS version 8.10.0 or higher.

Use create-resolve-app package to create a new reSolve application. The easiest way is to use npx

npx create-resolve-app my-awesome-app
cd my-awesome-app
npm run dev
You can also use npm or yarn tools

npm

Note: Installing a package globally may require administrative privileges.

npm i -g create-resolve-app
create-resolve-app my-awesome-app
cd my-awesome-app
npm run dev

yarn

yarn create resolve-app my-awesome-app
cd my-awesome-app
yarn run dev

Your application will be running at http://localhost:3000/.

Creating a new app with a code example

There are several code examples provided. You can add code from these examples into your projects. To list the available examples use the create-resolve-app -h command.

To create a new application with the code of the specific example use the create-resolve-app command with the -e flag followed by the example's name.

For instance, to run the shopping-list example, run:

npx create-resolve-app resolve-example -e shopping-list

πŸ“š Documentation

You can find reSolve documentation in the docs section.

To get started with reSolve, see the step-by-step tutorial.

πŸ“’ Get in Touch

reSolve is developed by Developer Express Inc.

Analytics

Comments
  • Server clustering configuration possible?

    Server clustering configuration possible?

    Is your feature request related to a problem? Please describe.

    Reading through the reSolve documentation, I'm specifically curious about whether clustering is natively supported. Specifically, the ability for multiple reSolve servers to be run in a cluster, where a given aggregate state is accessible to every server across the cluster, and where events can be emitted and processed by any member of the cluster.

    Looking through the Application Configuration documentation, the only potentially relevant information I've found is in the eventBroker section, where you can configure publisher and consumer settings. If I want to spin up multiple reSolve servers, should I set both of these configuration options on every server?

    I'd also like to know if configuring the eventBroker will also allow multiple reSolve servers to cluster in the way I've mentioned?

    An example use-case for this is deploying a reSolve application into a kubernetes cluster. The application will serve an API which will dispatch commands to aggregates. You will likely want multiple instances (pods) of the server running, for availability's sake, but these instances should be aware of each-other. Otherwise, you have no way to guarantee a given aggregate is unique across the cluster of servers, you risk aggregate state getting out-of-sync between servers, etc.

    Am I misunderstanding the design principles of the reSolve framework? Any clarity is appreciated here. Thanks for your input.

    opened by dwmcc 13
  • Detecting whether an aggregate exists

    Detecting whether an aggregate exists

    I think it would be useful if there was a built-in mechanism to detect whether an aggregate exists (in a command handler function) - reSolve knows this, since it has just attempted to retrieve the aggregate before the function is called. Unfortunately, the information is not passed on to the command handler and I am left to my own devices to figure it out. Since many aggregates require this logic to avoid duplicates, there is room for improvement here.

    Currently, the only "good" option is to handle a special aggregate field which denotes specifically whether the aggregate exists or not. (Note - I'm aware of several other approaches that are worse than this - please let me know in case you need me to elaborate.)

    So I'd have this in thing.commands.js:

    createThing: (aggregate, { payload: { ... } }) => {
      if (aggregate.exists) throw new Error('Thing exists');
      ...
    }
    

    And then this in thing.projection.js:

    [THING_CREATED]: (aggregate) => ({
        ...aggregate,
        exists: true,
    }),
    

    Obviously this approach works - but I don't think it should be necessary. It's boilerplate, required for almost any aggregate, and all just to detect a piece of information that is already known to reSolve!

    I suggest we use one of these two approaches:

    1. Pass a flag to the command function that indicates whether the aggregate is new (i.e. equal to its initial state)
    2. Pass the aggregate version to the command function - this mysteriously turns up in the event structure after the command function completes. I have to admit I don't exactly understand how this version is counted, or why it would be included in the event, but I suspect that the version exists already before the command function is called even for a new aggregate and could therefore be used as an indicator.
    opened by oliversturm 10
  • Current Status of Project and Future Plans?

    Current Status of Project and Future Plans?

    Hi,

    Thanks for sharing ResolveJS.

    However, it's unclear from web site and GitHub repository what is the actual current status of the project, e.g. limitations, and future plans.

    It would be great to have a page with description of current limitations and future plans, possibly with an estimated timeline, for ResolveJS.

    I have ascertained some limitations by reading through issues, documentation, and StackOverflow questions but this is not optimal or transparent.

    This would give me more confidence in committing a project to use ResolveJS.

    Thanks, Ashley.

    PS Apologies if I missed these somewhere...

    opened by AshleyAitken 7
  • How to validate aggregate Id from client on create command?

    How to validate aggregate Id from client on create command?

    At the moment we generate aggregate id and send it from a client on the create command. See Shopping List example: https://github.com/reimagined/resolve/blob/master/examples/shopping-list/client/components/ShoppingListCreator.js#L24

    I discussed this with developers: pros The user creates id and it could be a meaningful value for navigation or something else. Theoretically, it is just a string and should not break anything.

    cons In practice, we can send a huge string as id and broke app navigation. We have no place where to put validation for aggregate id on the server side.(update we can validate it in the command handler. Maybe need some docs on how to do.)

    opened by krutilin 7
  • appConfig - are the file paths really necessary?

    appConfig - are the file paths really necessary?

    The structure of the config blocks for aggregates, read models and other parts requires me to pass the relative path for each source code file:

      aggregates: [
        {
          name: 'aggregate-name',
          commands: 'common/aggregates/aggregate-name.commands.js',
          projection: 'common/aggregates/aggregate-name.projection.js',
        },
      ],
    

    This seems unusual, and extra work for maintenance. Of course there are many ways of building up this structure. I think there are two aspects that are strange for reSolve:

    1. The fact that the file names are given as they are
    2. The forced separation of commands and projections - a bit more opinionated than necessary.

    To provide an example of a contrasting implementation, here is some code from a demo that uses my own CQRS/ES framework. This is an aggregate implementation - never mind the details, but you can see that all aspects are handled in the same place. Of course I would still be free to separate command and projection related code - this way it's left to the dev which way they prefer.

    // aggregates/customer.js
    module.exports = {
      initial: () => ({}),
    
      commands: {
        CREATE: (aggregate, payload) => {
          doesntExist(aggregate);
          has(payload, 'name');
          return { type: 'CUSTOMER_CREATED', payload };
        },
    
        UPDATE: (aggregate, payload) => {
          exists(aggregate);
          has(payload, 'name');
          return { type: 'CUSTOMER_UPDATED', payload };
        }
      },
    
      projections: {
        CUSTOMER_CREATED: (aggregate, { timestamp }) => ({
          ...aggregate,
          creationTimestamp: timestamp
        })
      }
    };
    

    And then I have this to accumulate all aggregates:

    // aggregates/index.js
    module.exports = {
      customer: require('./customer'),
      order: require('./order')
    };
    

    I think this is a pretty compact and standard structure without enforced maintenance overhead. Couldn't the reSolve config work this way?

    opened by oliversturm 6
  • Example of alternative interface other than HTTP

    Example of alternative interface other than HTTP

    I am hoping to figure out a way to interface with my reSolve service from a local queue worker, rather than having events posted to an API endpoint.

    For example, if I wanted to have a worker consuming messages from an SQS queue - Ideally I would not need to then make an HTTP requests to get that event ingested. I would much rather simply be able to issue commands to aggregates from the worker. I originally thought a custom module may be a possible route - but the documentation in that area is pretty sparse.

    Would love some guidance on an alternative to posting commands to an HTTP endpoint, and instead issuing them directly from a worker.

    Even exposing the underlying express server in some way, ideally with access to the bootstrapped resolve instance. Right now it seems the express server is a black box.

    opened by Iodine- 6
  • Lerna & socket.io issue

    Lerna & socket.io issue

    1. Lerna does not perform correct bootstrapping for dependent modules, so when launching examples from it's appropriate directories, node_modules will not installed, so webpack/babel plugins can't be found
    2. Socket.io server part library perform including dependent library in run-time, which is incompatible with bundling mechanism. Should be researched, how to fix it in general case, and socket.io, in particular.
    bug 
    opened by IhostVlad 5
  • Add AMQP support

    Add AMQP support

    Is your feature request related to a problem? Please describe. Not necessarily.

    Describe the solution you'd like Like ApiHandlers, but for AMQP queues/messages.

    Describe alternatives you've considered I'm currently resolving (hacking) this by starting an AMQP consumer that does a local HTTP request to an API handler (for every message on a queue) that can map the message itself to a command. I would like to access the resolve context when consuming AMQP messages.

    Additional context Adding handlers for similar wire-level protocols (or those covering this and more like Kafka) might be interesting too.

    opened by bartbrinkman 0
  • Deno support

    Deno support

    Is your feature request related to a problem? Please describe. Deno and Edge functions are becoming more and more popular with services such as Supabase functions now using them.

    Im wonding if resolve would ever be able to support deno?

    Describe the solution you'd like A build of resolve that supports deno

    opened by mikecann 0
  • 'lambda@edge timeout' error occurs when polling data

    'lambda@edge timeout' error occurs when polling data

    'lambda@edge timeout' error occurs when polling data continuously and requests stop for some time

    STR:

    1. Open Dashboard Projects page with several not empty projects ( ask for an invitation to login on https://ddev.testcafe.io ). it makes requests for getLastBuilds resolver
    2. Wait for a while (an hour or more, tab goes into inactive mode ) .
    3. After awakening the lambda edge timeout error should appear.

    Screenshots image

    UPD: endpoint is endpoint api/query/Builds/getLastBuilds?projectIds=

    bug 
    opened by AlexanderMoiseev 0
  • Read-model projection Init handler eliminates errors

    Read-model projection Init handler eliminates errors

    Describe the bug Read-model projection Init handler eliminates errors if one occurs.

    To Reproduce Create Init handler with erroneous behaviour

    Init: async (store) => {
      await store.defineTable("abc", { indexes: {"abc": "string" }, fields: [] })
      await store.defineTable("abc", { indexes: {"abc": "string" }, fields: [] })
    }
    

    Read-model with such Init handler failed to build, but error is hidden

    Expected behaviour Read-model should crash with error message something like "Duplicate table name"

    Desktop (please complete the following information):

    • ReSolve Version: 0.33.15
    opened by IhostVlad 0
Releases(V0.34.3)
Owner
ReImagined
DevExpress reimagined project
ReImagined
DDD/Clean Architecture inspired boilerplate for Node web APIs

Node API boilerplate An opinionated boilerplate for Node web APIs focused on separation of concerns and scalability. Features Multilayer folder struct

Talysson de Oliveira Cassiano 3k Dec 30, 2022
Fast and type-safe full stack framework, for TypeScript

Fast and type-safe full stack framework, for TypeScript Why frourio ? Even if you write both the frontend and backend in TypeScript, you can't statica

frourio 1.1k Dec 26, 2022
This is MERN Stack Ecommerce Project Made to Teach MERN Stack on YouTube

MERN E-COMMERCE TUTORIAL Hi! My name is Abhishek Singh, I have created this tutorial to teach MERN Stack for free on YouTube. Prerequisite Must have b

Abhishek Singh 558 Jan 5, 2023
Elegant and all-inclusive Node.Js web framework based on TypeScript. :rocket:.

https://foalts.org What is Foal? Foal (or FoalTS) is a Node.JS framework for creating web applications. It provides a set of ready-to-use components s

FoalTS 1.7k Jan 4, 2023
A nodejs module for local and remote Inter Process Communication with full support for Linux, Mac and Windows

A nodejs module for local and remote Inter Process Communication with full support for Linux, Mac and Windows

Rifa Achrinza 15 Sep 28, 2022
Noderlang - Erlang node in Node.js

Noderlang allows Node.js programs to easily operate in BEAM environments

devsnek 2 Mar 31, 2022
Modern framework for fast, powerful React apps

FUSION.JS Modern framework for fast, powerful React apps What is it? fuΒ·sion β€” noun The process or result of joining two or more things together to fo

Fusion.js 1.5k Dec 30, 2022
πŸ¦„ 0-legacy, tiny & fast web framework as a replacement of Express

tinyhttp ⚑ Tiny web framework as a replacement of Express ?? tinyhttp now has a Deno port (work in progress) tinyhttp is a modern Express-like web fra

v 1 r t l 2.4k Jan 3, 2023
The most powerful headless CMS for Node.js β€” built with GraphQL and React

A scalable platform and CMS to build Node.js applications. schema => ({ GraphQL, AdminUI }) Keystone Next is a preview of the next major release of Ke

KeystoneJS 7.3k Jan 4, 2023
:desktop_computer: Simple and powerful server for Node.js

server.js for Node.js Powerful server for Node.js that just works so you can focus on your awesome project: // Include it and extract some methods for

Francisco Presencia 3.5k Dec 31, 2022
πŸš€ A RESTful API generator for Node.js

A RESTful API generator rest-hapi is a hapi plugin that generates RESTful API endpoints based on mongoose schemas. It provides a powerful combination

Justin Headley 1.2k Dec 31, 2022
nact β‡’ node.js + actors β‡’ your services have never been so Β΅

nact β‡’ node.js + actors your services have never been so Β΅ Any and all feedback, comments and suggestions are welcome. Please open an issue if you fin

Natalie Cuthbert 1k Dec 28, 2022
A Programming Environment for TypeScript & Node.js built on top of VS Code

Programming Environment for TypeScript & Node.js A battery-included TypeScript framework built on top of Visual Studio Code Website Kretes is a progra

Kretes 677 Dec 11, 2022
Clock and task scheduler for node.js applications, providing extensive control of time and callback scheduling in prod and test code

#zeit A node.js clock and scheduler, intended to take place of the global V8 object for manipulation of time and task scheduling which would be handle

David Denton 12 Dec 21, 2021
In-memory filesystem with Node's API

In-memory filesystem with Node's API

Vadim Dalecky 1.4k Jan 4, 2023
Micro type-safe wrapper for Node.js AMQP library and RabbitMQ management.

Micro type-safe wrapper for AMQP library and RabbitMQ management Description Section in progress. Getting Started Qupi can be installed by Yarn or NPM

Grzegorz Lenczuk 2 Oct 5, 2021
A simple boilerplate generator for your node express backend project! πŸš€

A simple boilerplate generator for your node express backend project! ??

Gunvant Sarpate 35 Sep 26, 2022
wolkenkit is an open-source CQRS and event-sourcing framework based on Node.js, and it supports JavaScript and TypeScript.

wolkenkit wolkenkit is a CQRS and event-sourcing framework based on Node.js. It empowers you to build and run scalable distributed web and cloud servi

the native web 1.1k Dec 26, 2022
This is a full-stack exercise tracker web application built using the MERN (MongoDB, ExpressJS, ReactJS, NodeJS) stack. You can easily track your exercises with this Full-Stack Web Application.

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

WMouton 2 Dec 25, 2021
🦫 A simple way to implement event sourcing in TypeScript

✨ Better DevX for Event Sourcing in TypeScript Castore provides a unified interface for implementing Event Sourcing in TypeScript. Define your events

Theodo.FR 17 Nov 18, 2022