chairo
chairo ("happy" in ancient Greek: χαίρω) is a Seneca micro-services plugin
for hapi. The plugin integrates the Seneca functionality into
hapi and provide tools to map its actions to server methods and views for easy access.
Lead Maintainer - Wyatt Preul
Usage
Plugin Registration
chairo is registered with a hapi server using the server.register()
method. Once
registered it decorates the server
object with a reference to the seneca
object initialized
using the provided plugin options. Default plugin options:
You can add a custom seneca
web plugin by passing in a function on the web
property. If web
is passed in, then the default web plugin for seneca is
disabled. web
must be a function to add custom web functionality. To disable
the seneca-web plugin set web
to false
.
const Chairo = require('chairo');
const Hapi = require('hapi');
const server = new Hapi.Server();
server.connection();
server.register({ register: Chairo }, function (err) {
let id = 0;
server.seneca.add({ generate: 'id' }, function (message, next) {
return next(null, { id: ++id });
});
server.seneca.act({ generate: 'id' }, function (err, result) {
});
});
In addition, the hapi request object is decorated with a reference to the seneca
object for
easy access:
server.route({
method: 'POST',
path: '/id',
handler: function (request, reply) {
request.seneca.act({ generate: 'id' }, function (err, result) {
if (err) {
return reply(err);
}
return reply(result);
});
}
});
server.action(name, pattern, [options])
Maps a Seneca action pattern to a hapi
server method
where:
name
- the server method name (same as the name used in server.method()
).pattern
- the Seneca action pattern (e.g. 'generate:id'
or { generate: 'id' }
) to map.options
- optional settings options where:
cache
- method caching options (same as the name used in server.method()
).generateKey
- method generating custom cache key (same as the name used in server.method()
).
const Chairo = require('chairo');
const Hapi = require('hapi');
const server = new Hapi.Server();
server.connection();
server.register(Chairo, function (err) {
var id = 0;
server.seneca.add({ generate: 'id' }, function (message, next) {
return next(null, { id: ++id });
});
server.seneca.add({ calc: 'average' }, function (message, next) {
return next(null, { average: ( message.samples.dataset.values[0] + message.samples.dataset.values[0] ) / 2 });
});
server.action('generate', 'generate:id', { cache: { expiresIn: 1000, generateTimeout: 3000 } });
server.action('average', 'calc:average', { cache: { expiresIn: 1000, generateTimeout: 3000 } }, generateKey: function (message) {
return 'average-' + message.samples.dataset.values[0] + ':' + message.samples.dataset.values[1];
});
server.start(function () {
server.methods.generate(function (err, result1) {
server.methods.generate(function (err, result2) {
server.methods.average({ samples: { dataset: values: [2, 3] } }, function (err, avg1) {
server.methods.average({ samples: { dataset: values: [2, 3] } }, function (err, avg2) {
});
});
});
});
});
});
reply.act(pattern)
Sends back a handler response using the result of a Seneca action where:
pattern
- the Seneca action called to generate the response.
const Chairo = require('chairo');
const Hapi = require('hapi');
const server = new Hapi.Server();
server.connection();
server.register(Chairo, function (err) {
var id = 0;
server.seneca.add({ generate: 'id' }, function (message, next) {
return next(null, { id: ++id });
});
server.route({
method: 'POST',
path: '/id',
handler: function (request, reply) {
return reply.act({ generate: 'id' });
}
});
});
In addition, the act
handler shortcut is also provided:
server.route({
method: 'POST',
path: '/id',
handler: { act: 'generate:id' }
});
reply.compose(template, context, [options])
Renders a template view using the provided template and context where:
template
- the view engine template (same as the name used in
reply.view()
).context
- the context object used to render the template. Chairo
provides a special key $resolve
where you can map context variables to Seneca actions matching they key's value pattern. Each of the services mapped to keys is resolved and the resultant key value maps are copied to the context root before redering the template.options
- optional settings passed to reply.view()
.
It requires the vision
plugin to be registered with Hapi.
const Chairo = require('chairo');
const Handlebars = require('handlebars');
const Vision = require('vision');
const Hapi = require('hapi');
const server = new Hapi.Server();
server.connection();
server.register([Chairo, Vision], function (err) {
server.seneca.add({ lookup: 'date' }, function (message, next) {
return next(null, { date: (new Date()).toString() });
});
server.seneca.add({ load: 'user' }, function (message, next) {
return next(null, { name: message.name });
});
server.views({
engines: { html: Handlebars },
path: __dirname + '/templates'
});
server.route({
method: 'GET',
path: '/',
handler: function (request, reply) {
var context = {
$resolve: {
today: 'lookup:date',
user: { load: 'user', name: 'john' }
},
general: {
message: 'hello!'
}
};
return reply.compose('example', context);
}
});
});
Using the template ./templates/example.html
:
<div>
<h1>{{today.date}}</h1>
<h2>{{user.name}}</h2>
<h3>{{general.message}}</h3>
</div>
In addition, the compose
handler shortcut is also provided:
server.route({
method: 'POST',
path: '/id',
handler: {
compose: {
template: 'example',
context: {
$resolve: {
today: 'lookup:date',
user: { load: 'user', name: 'john' }
},
general: {
message: 'hello!'
}
}
}
}
});