https://github.com/wechaty/cqrs
An event-driven architecture wrapper for Wechaty that applies the CQS principle by using separate Query and Command messages to retrieve and modify the bot state, respectively.
https://github.com/wechaty/cqrs
cqrs ddd domain-driven-design ducks event-driven redux rxjs
Last synced: 7 months ago
JSON representation
An event-driven architecture wrapper for Wechaty that applies the CQS principle by using separate Query and Command messages to retrieve and modify the bot state, respectively.
- Host: GitHub
- URL: https://github.com/wechaty/cqrs
- Owner: wechaty
- License: apache-2.0
- Created: 2022-03-06T04:51:22.000Z (almost 4 years ago)
- Default Branch: main
- Last Pushed: 2023-07-26T12:45:18.000Z (over 2 years ago)
- Last Synced: 2025-06-06T10:11:35.039Z (7 months ago)
- Topics: cqrs, ddd, domain-driven-design, ducks, event-driven, redux, rxjs
- Language: TypeScript
- Homepage: https://paka.dev/npm/wechaty-cqrs
- Size: 595 KB
- Stars: 6
- Watchers: 2
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# CQRS Wechaty
[](https://www.npmjs.com/package/wechaty-cqrs)
[](https://github.com/wechaty/cqrs/actions?query=workflow%3ANPM)
[](https://github.com/huan/ducks#3-ducksify-extension-currying--ducksify-interface)
[](https://github.com/Chatie/tsconfig/issues/16)
An event-driven architecture wrapper for Wechaty
that applies the CQS principle
by using separate Query and Command messages
to retrieve and modify the bot state,
respectively.

> Image source: [Introducing Derivative Event Sourcing](https://www.confluent.io/blog/event-sourcing-vs-derivative-event-sourcing-explained/)
## Command Query Responsibility Separation (CQRS)
> Command query responsibility separation (CQRS) generalises CQS
to message-driven and event-driven architectures:
it applies the CQS principle by using separate Query and Command messages
to retrieve and modify data, respectively.
>
> — [Wikipedia: Command–query separation](https://en.wikipedia.org/wiki/Command%E2%80%93query_separation)

> Image source: [CQRS (command query responsibility segregation)](https://www.techtarget.com/searchapparchitecture/definition/CQRS-command-query-responsibility-segregation)
## Motivation
Can we use Wechaty by only sending / receiving the [Plain Old JavaScript Object (POJO)](https://masteringjs.io/tutorials/fundamentals/pojo)?
That's an Event-driven way, which will give us the following benifites:
1. Better integration with Domain-driven Design (DDD)
1. Decouple the sub-systems with the Wechaty instance completely
1. Enable using Wechaty with Microservices
1. Make it possible for providing an API endpoint with JSON request/responses
1. etc.
So we decided to support the Event-driven Architecture
by enabling the Event-driven Programming with Wechaty
by publishing the [wechaty-cqrs](https://npmjs.com/package/wechaty-cqrs) NPM module.
## Features
1. Convert Wechaty instance to a messaging `bus$` with the `from()` function.
1. Well-defined `commands`, `queries`, `responses`, and `events` payload creators.
1. A great `execute$()` helper function for sending the events
to the bus and get back the response.
1. Well-defined `events$` for the Wechaty events
1. Well-defined `sayables` for build all the message contents
1. Static typing with TypeScript with all events & streams
1. Working perfect with the powerful RxJS
## Usage
### Install
```sh
npm install wechaty-cqrs wechaty
```
### Quick start
Here's the CQRS version of the Wechaty bot usage:
```ts
import * as CQRS from 'wechaty-cqrs'
import * as WECHATY from 'wechaty'
import { filter, map, mergeMap } from 'rxjs/operators'
const wechaty = WECHATY.WechatyBuilder.build()
await wechaty.init()
const bus$ = CQRS.from(wechaty)
bus$.pipe(
filter(CQRS.is(CQRS.events.MessageReceivedEvent)),
// MessageReceivedEvent -> Sayable
map(messageId => CQRS.queries.GetSayablePayloadQuery(
messageReceivedEvent.meta.puppetId,
messageId,Diagrams
)),
mergeMap(CQRS.execute$(bus$)),
// Log `sayable` to console
).subscribe(sayable =>
console.info('Sayable:', sayable),
)
bus$.next(CQRS.commands.StartCommand(wechaty.puppet.id))
```
Learn how to build a Ding Dong BOT with CQRS from our [examples/ding-dong-bot.ts](https://github.com/wechaty/cqrs/blob/main/examples/ding-dong-bot.ts)
## Getting Started
Here's a video introduction for CQRS Wechaty with live demo, presented by Huan:
[](https://youtu.be/kauxyPVa0jo)
> YouTube:
The getting started [ding-dong-bot.ts](https://github.com/wechaty/getting-started/blob/main/examples/cqrs/ding-dong-bot.ts)
in the video:
## Architecture Diagrams

```mermaid
graph LR
classDef event fill:DarkGoldenRod
classDef command fill:blue
classDef query fill:green
Diagrams
subgraph Command
C(VerbNounCommand):::command
end
subgraph Response
RC(VerbNounCommandResponse)
RQ(GetNounQueryResponse)
end
subgraph Query
Q(GetNounQuery):::query
end
subgraph Event
ER(ReceivedEvent):::event
end
C-->RC
ER-->ER
Q-->RQ
```
### Command
```mermaid
sequenceDiagram
participant Bus
participant Redux
participant Wechaty
Bus->>Redux: ExecuteCommand
Redux->>Wechaty: Call
Wechaty->>Redux: Call Return (void)
Redux->>Bus: ExecuteCommandResponse
```
### Query
```mermaid
sequenceDiagram
participant Bus
participant Redux
participant Wechaty
Bus->>Redux: GetNounQuery
Redux->>Wechaty: Call
Wechaty->>Redux: Call Return (value)
Redux->>Bus: GetNounQueryResponse
```
### Event
```mermaid
sequenceDiagram
participant Bus
participant Redux
participant Wechaty
Wechaty->>Redux: ReceivedEvent
Redux->>Bus: ReceivedEvent
```
## Data Transfer Object (DTO)
A [Data Transfer Object (DTO)](https://en.wikipedia.org/wiki/Data_transfer_object)
is an object that carries data between processes.
CQRS Wechaty has encapsulated all the events to DTOs, exported by:
```ts
// You will get DTOs from CQRS.{commands,queries} module
import * as CQRS from 'wechaty-cqrs'
/**
* Examples: building Data Transfer Object for
* - `DingCommand`
* - `GetIsLoggedInQuery
*/
const dingCommand = CQRS.commands.DingCommand(...)
const getIsLoggedInQuery = CQRS.queries.GetIsLoggedInQuery(...)
// Use them as you needed
```
Learn more from the [source code](src/dto/actions/)
## API Reference
Read CQRS Wechaty API Reference at:
## How to contribute
### How to add a new command/query
The following steps need to be followed:
1. Duck
1. Add a new [type](src/duck/types/queries.ts) to the `commands` or `queries`
1. Add a new [action](src/duck/actions/queries.ts) to the `request` and `response`
1. Add a new [epic](src/duck/epics/queries) to call the async API
1. DTO
1. Export new added `Command`/`Query` from
[commands](src/dto/actions/commands.ts)/[queries](src/dto/actions/queries.ts)
1. Export new added `Response` from [responses](src/dto/actions/responses.ts)
1. Writing unit tests.
## Blogs
- [Refactoring Friday BOT with NestJS, Domain-driven Design (DDD), and CQRS, @huan, Feb 27, 2022](https://wechaty.js.org/2022/02/27/refactoring-friday-bot-with-nestjs-ddd-cqrs/)
## Resources
- [Layers in DDD microservices](https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/ddd-oriented-microservice#layers-in-ddd-microservices)
- Effective Aggregate Design
- [Part I: Modeling a Single Aggregate](https://www.dddcommunity.org/wp-content/uploads/files/pdf_articles/Vernon_2011_1.pdf)
- [Part II: Making Aggregates Work Together](https://www.dddcommunity.org/wp-content/uploads/files/pdf_articles/Vernon_2011_2.pdf)
- [Part III: Gining Insight Through Discovery](https://www.dddcommunity.org/wp-content/uploads/files/pdf_articles/Vernon_2011_3.pdf)
- [Domain-Application-Infrastructure Services pattern](https://badia-kharroubi.gitbooks.io/microservices-architecture/content/patterns/tactical-patterns/domain-application-infrastructure-services-pattern.html)
## History
### main v1.15 (Apr 20, 2022)
1. rename all duck events' name from `camelCase` to `SNAKE_CASE`.
(i.e. `dingCommand` -> `DING_COMMAMD`)
### v1.12 (Mar 27, 2022)
1. Classify action builders so that they will be compatible with Class events
with NestJS [#1](https://github.com/wechaty/cqrs/issues/1)
1. `execute$()` helper function for sending the events to the bus
and get back the response, with automatically type inferring.
1. lots of typing enhancements.
Learn more from [PR #3](https://github.com/wechaty/cqrs/pull/3)
## v0.10 (Mar 17) Beta release
- v0.9 (Mar 17,2022): Refactoring(clean) module exports
- v0.7 (Mar 16, 2022): Refactoring `execute$` with `duck.actions` builders.
- v0.6 (Mar 13, 2022): Alpha release.
- v0.4 (Mar 13, 2022): CQRS Ding/Dong BOT works as expected.
- v0.2 (Mar 11, 2022): Unit tests all passed, DevOps enabled.
- v0.0.1 (Mar 6, 2022): Init README & Draft design.
## Author
[Huan LI](https://github.com/huan)
([李卓桓](http://linkedin.com/in/zixia)),
[Microsoft Regional Director](https://rd.microsoft.com/en-us/huan-li),
[](https://stackexchange.com/users/265499)
## Copyright & License
- Code & Docs © 2022 Huan (李卓桓) \
- Code released under the Apache-2.0 License
- Docs released under Creative Commons