Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Getting started documentation for Node.js #22

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
251 changes: 251 additions & 0 deletions src/docs/asciidoc/getting-started-eventuate-tram-nodejs.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
[[getting-started]]
== Getting started with Eventuate Tram for Node.js

Learn how to get started with https://github.com/eventuate-tram/eventuate-tram-core[Eventuate Tram], a framework for transactional messaging.
Eventuate Tram sends and receives messages as part of a database transaction ensuring that your application atomically updates the database and publishes messages.
Currently, it supports the following databases:

* Transaction log tailing: MySQL

And, the following message brokers:

* Apache Kafka

=== See also

* link:./about-eventuate-tram.html[Overview of EventuateTram]
* https://eventuate.io/exampleapps.html[Tram example applications]
* The https://github.com/eventuate-tram/eventuate-tram-core[Eventuate Tram Github repository]
* The https://github.com/eventuate-tram/eventuate-tram-sagas[Eventuate Tram Sagas Github repository]
* The https://www.manning.com/books/microservices-patterns[Microservices Patterns] book

=== JavaDocs

* See the https://eventuate.io/docs/javadoc/eventuate-tram/eventuate-tram.html[Eventuate Tram JavaDocs].

=== Project setup

Latest library version:

image::https://badge.fury.io/js/eventuate-tram-core-nodejs.svg[link="http://npmjs.com/package/eventuate-tram-core-nodejs"]

=== Transactional messages

Eventuate Tram has APIs for sending and receiving messages as part of a database transaction.

==== Sending messages

Send a message using `MessageProducer`:

[source,javascript]
----
const knex = require('../lib/mysql/knex');
const { MessageProducer } = require('eventuate-tram-core-nodejs');
const messageProducer = new MessageProducer();
const topic = 'test-topic';

const payload = { message: 'Test kafka subscription' };
const message = { payload, headers: { PARTITION_ID: 0, DATE: new Date().getTime() }};

const trx = await knex.transaction();
await messageProducer.send(topic, message, trx);
await trx.commit();
----

See this example of https://github.com/eventuate-tram/eventuate-tram-core-nodejs/blob/master/test/MessageProducer-spec.js#L34-L39[sending messages].

==== Consuming messages

Receive messages using `MessageConsumer`:

[source,javascript]
----
const { MessageConsumer } = require('eventuate-tram-core-nodejs');

const messageConsumer = new MessageConsumer();
const topic = 'test-topic';
const subscriberId = 'test-message-consumer-sb-id';

await messageConsumer.subscribe({ subscriberId, topics: [topic], messageHandler: async message => resolve() });
----

See this example of https://github.com/eventuate-tram/eventuate-tram-core-nodejs/blob/master/test/MessageConsumer-spec.js#L39[consuming messages].

=== Transactional domain events

The domain event package builds on the transaction messaging APIs.

==== Publishing domain events

Publish domain events using `DomainEventPublisher`:

[source,javascript]
----
const knex = require('../lib/mysql/knex');

const { MessageProducer, DomainEventPublisher } = require('eventuate-tram-core-nodejs');
const messageProducer = new MessageProducer();
const domainEventPublisher = new DomainEventPublisher({ messageProducer });

const aggregateType = 'Account';
const aggregateId = 'Fake_aggregate_id';
const events = [
{ amount: 10, _type: 'CreditApproved' },
{ amount: 20, _type: 'CreditApproved' },
{ amount: 30, _type: 'CreditApproved' },
{ amount: 40, _type: 'CreditApproved' },
];

const trx = await knex.transaction();
await domainEventPublisher.publish(aggregateType, aggregateId, events, { trx });
await trx.commit();
----

And with custom channel mapping:
[source,javascript]
----
const knex = require('../lib/mysql/knex');
const { MessageProducer, DomainEventPublisher } = require('eventuate-tram-core-nodejs');

class CustomChannelMapping {
constructor() {
// map "CustomerAccount" aggregate type to "Account"
this.mappings = new Map([['CustomerAccount', 'Account']]);
}
transform(channel) {
const mappingChannel = this.mappings.get(channel);
return mappingChannel || channel;
}
}

const messageProducer = new MessageProducer({ channelMapping: new CustomChannelMapping() });
const domainEventPublisher = new DomainEventPublisher({ messageProducer });

const aggregateType = 'Account';
const aggregateId = 'Fake_aggregate_id';
const events = [
{ amount: 10, _type: 'CreditApproved' },
{ amount: 20, _type: 'CreditApproved' },
{ amount: 30, _type: 'CreditApproved' },
{ amount: 40, _type: 'CreditApproved' },
];

const trx = await knex.transaction();
await domainEventPublisher.publish(aggregateType, aggregateId, events, { trx });
await trx.commit();
----

See this example of https://github.com/eventuate-tram/eventuate-tram-core-nodejs/blob/master/test/DomainEventPublisher-spec.js#L65-L81[Publishing events].


==== Consuming domain events

First, define `DomainEventHandlers`:

[source,javascript]
----

const aggregateType = 'Account';
const eventType = 'CreditApproved';

const domainEventHandlers = {
[aggregateType]: {
[eventType]: async (event) => {
console.log(event);
}
}
};
----

Second, configure a `DomainEventDispatcher`:

[source,javascript]
----
const { MessageConsumer, DomainEventDispatcher } = require('eventuate-tram-core-nodejs');

const messageConsumer = new MessageConsumer();
const eventDispatcherId = 'test-domain-event-dispatcher-id';

domainEventDispatcher = new DomainEventDispatcher({ eventDispatcherId, domainEventHandlers, messageConsumer });
await domainEventDispatcher.initialize();
----

Same with custom domain event mapping:

[source,javascript]
----
const { MessageConsumer, DomainEventDispatcher } = require('eventuate-tram-core-nodejs');

class CustomerDomainEventNameMapping {
constructor() {
this.mappings = {
[aggregateType]: new Map([[eventType, 'CustomerCreditApproved']])
};
}
externalEventTypeToEvent(aggregateType, eventTypeHeader) {
if (this.mappings[aggregateType]) {
return this.mappings[aggregateType].get(eventTypeHeader);
}
throw new Error('Unknown aggregate type');
}
}

const messageConsumer = new MessageConsumer();
const eventDispatcherId = 'test-domain-event-dispatcher-id';

domainEventDispatcher = new DomainEventDispatcher({ eventDispatcherId,
domainEventHandlers,
messageConsumer,
domainEventNameMapping: new CustomerDomainEventNameMapping()
});
await domainEventDispatcher.initialize();
----

See this example of https://github.com/eventuate-tram/eventuate-tram-core-nodejs/blob/master/test/DomainEventDispatcher-spec.js#L65-L84[Dispatching domain events].

=== Configuring the transport

===== Setup environment variables:

EVENTUATE_TRAM_KAFKA_BOOTSTRAP_SERVERS=localhost:9092
EVENTUATE_TRAM_MYSQL_HOST=localhost
EVENTUATE_TRAM_MYSQL_PORT=3306
EVENTUATE_TRAM_MYSQL_DATABASE=eventuate
EVENTUATE_TRAM_MYSQL_USERNAME=mysqluser
EVENTUATE_TRAM_MYSQL_PASSWORD=mysqlpw

=== Running the CDC service

In addition to a database and message broker, you will need to run the link:./cdc-configuration.html[Eventuate Tram CDC] service.
It reads events inserted into the database and publishes them to the message broker.
It is written using Spring Boot.
The easiest way to run this service during development is to use Docker Compose.

The https://github.com/eventuate-tram/eventuate-tram-core-examples-basic[Eventuate Tram Code Basic examples] project has an example https://github.com/eventuate-tram/eventuate-tram-core-examples-basic/blob/master/docker-compose.yml[docker-compose.yml file].

[source,yaml]
----
cdcservice:
image: eventuateio/eventuate-tram-cdc-mysql-service:0.4.0.RELEASE
ports:
- "8099:8080"
depends_on:
- mysql
- kafka
- zookeeper
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://mysql/eventuate
SPRING_DATASOURCE_USERNAME: mysqluser
SPRING_DATASOURCE_PASSWORD: mysqlpw
SPRING_DATASOURCE_DRIVER_CLASS_NAME: com.mysql.jdbc.Driver
EVENTUATELOCAL_KAFKA_BOOTSTRAP_SERVERS: kafka:9092
EVENTUATELOCAL_ZOOKEEPER_CONNECTION_STRING: zookeeper:2181
EVENTUATELOCAL_CDC_DB_USER_NAME: root
EVENTUATELOCAL_CDC_DB_PASSWORD: rootpassword
EVENTUATELOCAL_CDC_READER_NAME: MySqlReader
EVENTUATELOCAL_CDC_OFFSET_STORE_KEY: MySqlBinlog
EVENTUATELOCAL_CDC_MYSQL_BINLOG_CLIENT_UNIQUE_ID: 1234567890
EVENTUATELOCAL_CDC_READ_OLD_DEBEZIUM_DB_OFFSET_STORAGE_TOPIC: "false"
----

For more information, please see link:./cdc-configuration.html[Eventuate Tram CDC]