Skip to content
/ cqrs Public

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.

License

Notifications You must be signed in to change notification settings

wechaty/cqrs

Repository files navigation

CQRS Wechaty

NPM Version NPM Ducksify Extension ES Modules

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.

Command Query Responsibility Segregation (CQRS) Wechaty

Image source: Introducing Derivative Event Sourcing

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

Command Query Responsibility Segregation (CQRS) Pattern

Image source: CQRS (command query responsibility segregation)

Motivation

Can we use Wechaty by only sending / receiving the Plain Old JavaScript Object (POJO)?

That's an Event-driven way, which will give us the following benifites:

  1. Better integration with Domain-driven Design (DDD)
  2. Decouple the sub-systems with the Wechaty instance completely
  3. Enable using Wechaty with Microservices
  4. Make it possible for providing an API endpoint with JSON request/responses
  5. etc.

So we decided to support the Event-driven Architecture by enabling the Event-driven Programming with Wechaty by publishing the wechaty-cqrs NPM module.

Features

  1. Convert Wechaty instance to a messaging bus$ with the from() function.
  2. Well-defined commands, queries, responses, and events payload creators.
  3. A great execute$() helper function for sending the events to the bus and get back the response.
  4. Well-defined events$ for the Wechaty events
  5. Well-defined sayables for build all the message contents
  6. Static typing with TypeScript with all events & streams
  7. Working perfect with the powerful RxJS

Usage

Install

npm install wechaty-cqrs wechaty

Quick start

Here's the CQRS version of the Wechaty bot usage:

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

Getting Started

Here's a video introduction for CQRS Wechaty with live demo, presented by Huan:

CQRS Wechaty Getting Started

YouTube: https://youtu.be/kauxyPVa0jo

The getting started ding-dong-bot.ts in the video: https://github.com/wechaty/getting-started/blob/main/examples/cqrs/ding-dong-bot.ts

Architecture Diagrams

CQRS Events Structure

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
Loading

Command

sequenceDiagram
    participant Bus
    participant Redux
    participant Wechaty

    Bus->>Redux: ExecuteCommand
    Redux->>Wechaty: Call
    Wechaty->>Redux: Call Return (void)
    Redux->>Bus: ExecuteCommandResponse
Loading

Query

sequenceDiagram
    participant Bus
    participant Redux
    participant Wechaty

    Bus->>Redux: GetNounQuery
    Redux->>Wechaty: Call
    Wechaty->>Redux: Call Return (value)
    Redux->>Bus: GetNounQueryResponse
Loading

Event

sequenceDiagram
    participant Bus
    participant Redux
    participant Wechaty

    Wechaty->>Redux: ReceivedEvent
    Redux->>Bus: ReceivedEvent
Loading

Data Transfer Object (DTO)

A Data Transfer Object (DTO) is an object that carries data between processes.

CQRS Wechaty has encapsulated all the events to DTOs, exported by:

// 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

API Reference

Read CQRS Wechaty API Reference at: https://paka.dev/npm/wechaty-cqrs

How to contribute

How to add a new command/query

The following steps need to be followed:

  1. Duck
    1. Add a new type to the commands or queries
    2. Add a new action to the request and response
    3. Add a new epic to call the async API
  2. DTO
    1. Export new added Command/Query from commands/queries
    2. Export new added Response from responses
  3. Writing unit tests.

Blogs

Resources

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
  2. execute$() helper function for sending the events to the bus and get back the response, with automatically type inferring.
  3. lots of typing enhancements.

Learn more from PR #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 (李卓桓), Microsoft Regional Director, [email protected]

Profile of Huan LI (李卓桓) on StackOverflow

Copyright & License

  • Code & Docs © 2022 Huan (李卓桓) <[email protected]>
  • Code released under the Apache-2.0 License
  • Docs released under Creative Commons

About

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.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published