A lightweight implementation of a messaging framework for JavaScript/TypeScript - inspired by the Java™ Message Service API.
- Introduction
- Message Model
- Messaging domains
- Compatibility
- Installation
- Examples using the simplified API
- Contributing
- Credits
- License
jsms provides a common way for JavaScript programs to create, send and receive messages. It defines some messaging semantics and a corresponding set of JavaScript classes to build clients, servers and even message brokers using a single, unified message API. It was initially developed to eliminate boilerplate code by combining two partly redundant messaging solutions into one.
It can be used right out of the box in terms of an in-process mediator/event bus, but for connecting to a JMS broker or for using protocols/transports like for example STOMP over WebSocket, you can do so by supplying a custom connection class that integrates your own or other (3rd-party) communication implementations - see the simple HTTP-based sample implementation inside the examples folder for a starting point.
-
Specific communication protocols
-
A complete implementation of the Java™ Message Service API specs, since jsms targets a simplified and more lightweight approach
-
A threading/worker model (at least not for now) - therefore all send/receive functions are asynchronous by nature (using promises)
jsms messages are composed of the following parts:
-
Header - contains values used by both clients and providers to identify and route messages
-
Body - jsms defines only one type being any custom object literal
id | the id header field contains a value that uniquely identifies each message (uuid) |
destination | the topic or queue name |
expiration | the time in milliseconds when this message will expire or zero if the message shouldn't expire |
correlationID | used for matching replies/responses to original message |
jsms supports both major styles of messaging: Point-to-point (PTP) and Publish/subscribe (pub/sub).
Use PTP messaging when every message you send must be processed successfully by one consumer:
-
Each queue/message has only one consumer.
-
A sender and a receiver of a message have no timing dependencies. The receiver can fetch the message whether or not it was running when the client sent the message.
-
Queues retain all (up to maxSize) messages sent to them until the messages are consumed, the message expires or the queue is closed - messages aren't persisted.
An application may send messages to a queue by using a connection's QueueSender object. Messages can be consumed from a queue by using a connection's QueueReceiver object.
The JsmsService facade class provides a simplified API for both send and receive operations.
Topics take care of distributing the messages arriving from multiple publishers to its multiple subscribers:
-
Topics retain messages only as long as it takes to distribute them to current subscribers.
-
Each message may have multiple consumers.
-
Publishers and subscribers have a timing dependency. A client that subscribes to a topic can consume only messages published after the client has created a subscription.
An application may send messages to a topic by using a connection's TopicPublisher object. Messages can be consumed from a topic by using a connection's TopicSubscriber object.
The JsmsService facade class provides a simplified API for both publish and subscribe operations.
Node.js | 10.x or later (using CommonJS module format) |
Browsers | any ES6-compatible, tested with Chrome 76 and Firefox 68 |
In your project root:
$ npm install jsms
To enable logging, you have to include a log4js compliant framework like log4js-node - if no version of log4js can be found, then jsms simply does not output anything.
Important note for webpack users: if you don't use log4js, it must be excluded via module.noParse, otherwise you will run into an unresolved module dependency error.
For help with integrating jsms into your project, please refer to the bare-bones examples in the following repos:
These are just a few simple examples to give you a quickstart. For further information, please refer to the JSDoc comments, annotated tests and the examples folder.
const messageService = new JsmsService();
messageService.send("/some/queue", {abc: "xyz"})
.then(response => {
console.log(response.body); // expected output: {xyz: "abc"}
});
messageService.receive("/some/queue")
.then(message => {
console.log(message.body); // expected output: {abc: "xyz"}
return {xyz: "abc"};
});
JsmsService intercepts chained thens for point-to-point sends/receives to provide a more logical flow. This shouldn't encourage anybody to create fine-grained chatty interfaces, but might be useful sometimes and definitely is something notable since it differs from the expected promise default behavior:
const messageService = new JsmsService();
messageService.send("/some/queue", {request: "PING1"})
.then(response => {
console.log(response.body); // expected output: {response: "PONG1"}
return {request: "PING2"};
})
.then(response => {
console.log(response.body); // expected output: {response: "PONG2"}
});
messageService.receive("/some/queue")
.then(request => {
console.log(request.body); // expected output: {request: "PING1"}
return {response: "PONG1"};
})
.then(request => {
console.log(request.body); // expected output: {request: "PING2"}
return {response: "PONG2"};
});
const messageService = new JsmsService();
messageService.subscribe("/some/topic", message => {
console.log(message.body); // expected output: {xyz: "abc"}
});
messageService.publish("/some/topic", {xyz: "abc"});
Please keep in mind that this project is still in beta state, but if you find something important missing or not working right in your use case, don't hesitate and feel free to open an issue or to send me a pull request.
@log4js-node/log4js-api | homepage - show license |
uuid | homepage - show license |
MIT