Nestjs, External EventBus
Tags: javascript, eventbus, node, nestjs
Published: 2019-08-18 19:48:15

Hello friends! In this article, I wanna share one solution to implementing external `EventBus`. if you haven't been acquainted with `EventBus` yet, you can visit [this link](https://docs.nestjs.com/recipes/cqrs).
By default, Nestjs allows calling `event handler` only locally. It's a problem when we want to publish events via external `EventBus`, so I suggest [the following solution](https://github.com/sergey-telpuk/nestjs-external-eventbus). Bellow, I'll show a publisher which is based on `redis-pub`. Also, we can find a publisher for RabbitMQ.

`RedisPublisher`.

```ts
import {Injectable} from '@nestjs/common';
import {Client, ClientProxy, Transport} from '@nestjs/microservices';
import {AbstractPublisher} from '../abstract.publisher';


@Injectable()
export class RedisPublisher extends AbstractPublisher {
    TRANSPORT = Transport.REDIS;
    PATTERN = 'event_bus';

    @Client({
        transport: Transport.REDIS,
        options: {
            url: 'redis://:password123@redis:6379',
        },
    })
    client: ClientProxy;

    protected async send(pattern: any, data: any) {
        try {
            await this.client.send(pattern, data).toPromise();
        } catch (e) {
            this.log.error(e);
        }
    }
}

```
`AbstractPublisher` 
```ts 
import {IEvent, IEventPublisher} from '@nestjs/cqrs';
import {Transport} from './transport.enum';
import {Injectable, Logger} from '@nestjs/common';

@Injectable()
export abstract class AbstractPublisher implements IEventPublisher {
    abstract TRANSPORT: Transport;
    abstract PATTERN: string;

    constructor(
        protected readonly log: Logger,
    ) {

    }

    publish<T extends IEvent>(event: T): void {

        const data = {
            payload: event,
            event: event.constructor.name,
        };

        this.send(this.PATTERN, data);
    }

    protected abstract send(pattern: any, data: any): any;
}
```
 
As you can see, `RedisPublisher` extends  `AbstractPublisher` where is required to implement the `send` method. For a particular type of transport, we should implement own send method and add transport into the event. In common case, it's enough to start sending an event via transport.   

`ContrivedEvent`
```ts
export class ContrivedEvent implements IEventWithTransport {
    TRANSPORTS = [Transport.RMQ, Transport.DEF, Transport.REDIS];

    constructor(
    ) {}
}
...
import {IEvent} from '@nestjs/cqrs';
import {Transport} from '../transport.enum';

export interface IEventWithTransport extends IEvent {
    TRANSPORTS: Transport[];
}
...

export enum Transport {
    TCP = 0,
    REDIS = 1,
    NATS = 2,
    MQTT = 3,
    GRPC = 4,
    RMQ = 5,
    DEF = 6,
}

```
As you can see, there were used three kinds of transports: 
1. RabitMQ
2. Redis
3. Local

Using `EventBusTransport`:
```ts
import {Controller, Get} from '@nestjs/common';
import {EventBusTransport} from '../event-bus-transport/event.bus.transport';
import {ContrivedEvent} from '../events/contrived/contrived.event';

@Controller('/')
export class ContrivedController {

    constructor(
        readonly eventBusTransport: EventBusTransport,
    ) {}

    @Get('/contrived')
     contrived() {
        this.eventBusTransport.publish(new ContrivedEvent());
    }

}

```