grafka

A Nodejs/Typescript package for supporting event driven archeticutre inside nodejs app

Usage no npm install needed!

<script type="module">
  import grafka from 'https://cdn.skypack.dev/grafka';
</script>

README

Grandjs logo

Grafka

A Grandjs Package helper for applying event driver architecture on your monolothic application

Content

About

Grafka is a typescript package that helps you write high scalable web application using event driven architecture inside your monolothic application, so instead of calling your services inside the other functions, you can easily inject your services inside Grafka brokers and just fire event from anywhere inside your application and your services will work as a charm!

Features

  • Applying Event Driven Architecture on the level of app
  • Isolation between your services and controllers
  • Connect your services, controllers, repositories event without injecting your dependencies

Use Cases

Imagine you have a nodejs application that has users register, so when the user registers you should send an email or sms verification to verify his account, this action can be done normally by calling the mail service inside your controller and after saving the new user in the database, you call the mail service or sms service directly in your controller to send the verification But Grafka allows you to make your controller does one function which is for example saving the user in database, and then you use Grafka producer to trigger/fire an event and on the other hand you have consumers that listen for this event to work on so easily you can fire event, pass user data through this event and the consumer will call the mail service and send the verification automatically!

  • Multiple services works on the same data at the same time
  • services that should do an operation but being isolated from other services

Prerequisites

  • install nodejs on your machine/javascript browser
  • install typescript/javascript
  • initialize a new typescript project/javascript project

Dependencies

Grafka doesn't use dependencies to start using it unless you want to use Grafka decorators so you need to install and use typescript

Installing

npm i grafka

Usage

Grafka exposes to you a set of functions and classes that you can use to build your brokers, events and so on

import {Broker, UseBroker, Consumer, UseConsumer, Brokers, useProducer} from "grafka"

Architecture

Grafka Architecture

Grafka includes four main instances

  • Broker: Grafka exposes a Broker class that you can extend to build your own broker, This broker basically stores your consumers and topics
  • Topic: This is the path/name of message that your consumers inside the broker interested in
  • Producer: This instance is resbonsible on producing messages and these messages are sent to the broker and listened by the event emitter
  • Consumer: Each Topic inside a broker has group of consumers that they are interested in to get updates of that topic once a producer triggers an event

Grafka Event Life Cycle

Grafka State Diagram

Broker

Grafka Broker is an abstracted class that you can use to build a new broker instance which will host your topics, producers, consumers

Example

import {Broker} from "grafka";

To create a new Grafka Broker instance, you just need to instantiate this class ass the following:

import {Broker} from "grafka";

class UserBroker extends Broker{

}

Now You have an extended broker which you can use to add topics and consumers to it

Topic

To define a new topic for this broker you can use a decorator called Topic this decorator is a function that takes one argument which is a string refers to the path of the topic you want to create

|property|type|required|description| |-|-|-|-| |topic|string|true|the path of the topic you want to create|

Example

import {Broker, Topic} from "grafka";

@Topic("/notification")
class UserBroker extends Broker{

}

This will automatically inject a topic inside your broker, this topic path will be used later from the consumer to allow the consumer set the topics that it's interested in!

Producer

Producer is something you use to produce/trigger an event related to specific topic inside a specific broker, once this event is triggered the interested consumers with this event topic will receive a notification about this topic

You can use this producer from anywhere inside your application, what you need is just use function called useProducer to trigger an event with the following parameters

|parameter|type|required|description| |-|-|-|-| |BrokerName|string|true|the name of the broker that you want to produce an event in| |topic|string|true|A specific path that you want to trigger an event on| |args|any|false|the rest of arguments you want to pass to the consumers that they will be called once you trigger an event related to specific topic|


import {Broker, Topic, useProducer} from "grafka";

@Topic("/notification")
class UserBroker extends Broker{

}


const makeEvent = (username:string) => {
    // produce an event
    useProducer("UserBroker", "/notification", username);
}

As you can see the function we created will trigger an event once this function is called, this function takes one parameter which is a string that will sent it to the interested consuners once the event is triggered

Consumer

This is the interested things in your broker topics, the consumer basically is a function that will be called once an event is triggered from a producer on a specific topic

You have different ways to register consumers into brokers as the following:

  • Using Consumer decorator to decorate a method inside a class
  • Using UseConsumer to inject the consumer into a specific broker

Using Consumer Decorator

Grafka exposes to you a decorator function that you can use inside any class to inject this method as a consumer inside any broker you want, this decorator can be used if you are using typescript

Example

import {Broker, Topic, useProducer, Consumer} from "grafka";

@Topic("/notification")
class UserBroker extends Broker{

}

class UserService {
    @Consumer(UserBroker, ["/notification"])
    receiveNotification() {}
}

const makeEvent = (username:string) => {
    // produce an event
    useProducer("UserBroker", "/notification", username);
}

Consumer Decorator takes the following parameters

|parameter|type|required|description| |-|-|-|-| |Broker|string/Broker|true|This parameter specifies which broker you want to inject this consumer in, this barameter can be a string to specify the name of the broker or can be a broker class instance| |topics|Array(string)|true|specifies the topics that this consumer is interested in| |args|any|false|the rest of arguments that you want to pass to the consumer when it's called once the event is triggered|

Using UseConsumer Method

If you don't want to use decorators, you can use UseConsumer method which is can be used anywhere to inject a consumer into a specific broker

Example

import {Broker, Topic, useProducer, Consumer, UseConsumer} from "grafka";

@Topic("/notification")
class UserBroker extends Broker{

}

const NotificationConsumer = () => {
    console.log("this is consumer");
}

UseConsumer(UserBroker || "userBroker", ["/notification"], NotificationConsumer)
const makeEvent = (username:string) => {
    // produce an event
    useProducer("UserBroker", "/notification", username);
}

UseConsumer takes the following parameters:

|parameter|type|required|description| |-|-|-|-| |Broker|string/Broker|true|This parameter specifies which broker you want to inject this consumer in, this barameter can be a string to specify the name of the broker or can be a broker class instance| |topics|Array(string)|true|specifies the topics that this consumer is interested in| |executer|function|true|a function should be executed when a producer fires an event related to one of this consumer topics| |args|any|false|the rest of arguments that you want to pass to the consumer when it's called once the event is triggered|

When you use UseConsumer function or Consumer decorator, you can specify the topics that this consumer is interested in, if one of the specified topics is not defined in the broker before, the consumer function will add it automatically to the specified broker topics

Use The Broker

After defining the broker, now you need to use this broker to activate it and make it available to be consumed be producers and consumers, for that Grafka introduce a function called UseBroker this function can be used as a class decorator or can be used as a standalone function

UseBroker function parameters are as the following:

|parameters|type|required|description| |-|-|-|-| |Broker|Broker|true|this is the broker that you want to add to the consumed brokers|

Exampl

import {Broker, Topic, useProducer, Consumer, UseConsumer, UseBroker} from "grafka";


@Topic("/notification")
class UserBroker extends Broker{

}
// use this broker
UseBroker(UserBroker);

If you want to use this function as a class decorator, you can write something like this:

Exampl

import {Broker, Topic, useProducer, Consumer, UseConsumer, UseBroker} from "grafka";

// use this broker
@UseBroker
@Topic("/notification")
class UserBroker extends Broker{

}

Note the UseBroker decorator should be used at the top of the class other decorators