Hermes is a real-time messaging framework. It lets you connect a client with a broker and manage all the communication in between.
npm install --save hermesjs
- Express-like Routing and middlewares.
- Forwarding messages from Client to Broker and viceversa.
- Cancel the delivery (message will continue passing through middlewares, if any).
- Stop the message (message will not continue passing through middlewares).
- Answer back to client or broker, using same or different topic and payload.
Check examples repo.
Initializing a Hermes app is actually really easy:
const hermes = require('hermesjs');
const app = hermes();
This method is used to add configuration parameters to your Hermes app. Special
keys are client
and broker
.
For instance, you can specify your Socket.IO client adapter:
const socketio_adapter = require('hermesjs-socketio');
const socketio = socketio_adapter();
app.add('client', socketio);
or you can specify your MQTT broker adapter:
const mqtt_broker = require('hermesjs-mqtt');
const mqtt = mqtt_broker({
host_url: 'mqtt://test.mosquitto.org',
topics: 'hello/#'
});
app.add('broker', mqtt);
Use middlewares and routes. If you know how Connect/Express works, it's exactly the same:
Middlewares:
app.use((message, next) => {
if (message.payload === 'Hello!') {
console.log('-.- Hi!');
}
next();
});
Routes:
app.use('hello/:name', (message, next) => {
console.log(`Hello ${message.route.params.name}!`);
next();
});
HermesRouter
index.js
const hello = require('./routes/hello');
app.use('hello', hello);
routes/hello.js
const router = require('hermes').router();
router.use(':name', (message, next) => {
console.log(`Hello ${message.route.params.name}!`);
next();
});
router.use('world', (message, next) => {
console.log(`Hello world!`);
next();
});
router.in.client.use(':name', (message, next) => {
message.reply('hello/response', { msg: `Hello ${message.route.params.name} from Hermes!` });
});
module.exports = router;
Catch Errors
app.use((err, message, next) => {
console.log('Handle error here...');
next(err); // Optionally forward error to next middleware
});
It's for the same purpose as app.use
but this route/middleware will be only
executed if the message comes from the client.
app.in.client.use('hello/:name', (message, next) => {
console.log(`Hello from client, ${message.route.params.name}!`);
next();
});
It's for the same purpose as app.use
but this route/middleware will be only
executed if the message comes from the broker.
app.in.broker.use('hello/:name', (message, next) => {
console.log(`Hello from broker, ${message.route.params.name}!`);
next();
});
It will inject a message into the middleware pipeline as if it were coming from the broker. message
can be either an object containing topic
and payload
or a HermesMessage instance.
app.from.broker.send({
topic: 'hello/fran',
payload: {
greetings: 'Greetings from the broker'
}
});
It will inject a message into the middleware pipeline as if it were coming from the client. message
can be either an object containing topic
and payload
or a HermesMessage instance.
app.from.client.send({
topic: 'hello/fran',
payload: {
greetings: 'Greetings from the client'
}
});
Actually starts the application and listens for messages:
app.listen();
It stops the message from being delivered and processed by another middleware. It other words, this is a full stop. Message piping ends here.
app.use('hello/:name', (message, next) => {
// This will stop the hello/world message. Even if we call
// next, further middlewares will not be called.
if (message.route.params.name === 'world') message.stop();
next();
});
It cancels the delivery of the message but, unlike message.stop()
the message will continue
passing through the next middlewares.
function checkIsHelloWorld (message, next) {
// Message will not reach the other side if its topic is hello/world.
// If the message comes from the client it will never reach the broker and viceversa.
// However the message will still be routed onto next middlewares, if any.
if (message.route.params.name === 'world') return message.cancelDelivery();
}
app.use('hello/:name', checkIsHelloWorld, (message, next) => {
console.log('You will see this even if it is hello/world. Read comments above.');
next();
});
Replies back to the message sender. If the message was sent by client, it will reply to client. If message was sent by broker, it will reply to broker. It's easy, huh?
app.in.client.use('hello/:name', (message, next) => {
if (message.route.params.name === 'world') {
return message.reply('hello/world/response', 'Stop using hello world, please.');
}
next();
});
topic
and payload
arguments are both optional. Here you have a short explanation of every combination:
message.reply()
: It replies back to the same topic using same payload (echo).message.reply(payload)
: It replies back to the same topic using the given payload.message.reply(topic)
: It replies back to the the given topic using the same payload.message.reply(topic, payload)
: It replies back to the the given topic using the given payload.
Object containing all the params in the message topic, i.e.:
app.in.broker.use('hello/:name/:surname', (message, next) => {
// Given the `hello/tim/burton` topic, the params will look like:
// message.route.params = {
// name: 'tim',
// surname: 'burton'
// }
}
});
- MQTT adapter: https://github.com/hitchhq/hermes-mqtt
- Socket.IO adapter: https://github.com/hitchhq/hermes-socketio