mservice
v8.0.0
Published
Abstract microservice core
Downloads
20
Readme
Microservice core
This module provides boilerplate for microservice core and a few plugins for starters. It sets up convenient connect
and close
methods,
logging features, as well as input validation. At the same time it is an event emitter and may send log and other events silently.
Migration from 2.x to 3.x
Version 3 bring a neat feature of supporting multiple transports and request lifecycle. Please consult releases page on how to migrate your code
Usage
Extend Mservice class, populate plugins with array of their names. Currently supported:
amqp
cassandra
elasticsearch
http
logger
redisCluster
redisSentinel
router
socketIO
validator
Events:
ready
- when all plugins are upclose
- when all plugins were disconnectedplugin:connect:pluginName
,instance
plugin:close:pluginName
error
,err
- on critical error
Example
const path = require('path');
const Mservice = require('mservice');
const ld = require('lodash');
class UserService extends Mservice {
/**
* default options
* @type {Object}
*/
static defaultOpts = {
plugins: ['validator', 'logger', 'amqp', 'redisCluster'],
redis: {
hosts: [{
host: 'localhost',
port: 6379
}],
options: {
keyPrefix: 'nice'
}
},
amqp: {
transport: {
queue: 'roundrobin',
},
},
logger: {
defaultLogger: true,
},
// relative paths will be resolved relatively to the first dir of the file
// on the call stack that is not src/plugins/validator.js or src/index.js
// keep that in mind when creating instances of services
//
// if that's tricky - pass absolute paths!
validator: [ '../schemas' ],
}
constructor(opts = {}) {
super(ld.merge({}, UserService.defaultOpts, opts));
}
}
const userService = new UserService();
// methods that userService will have are explain below
Methods
initPlugin(mod, [conf])
Initializes plugin, which has 2 methods: .attach
- it would be called with service
as context and conf as first arg
When conf
is omitted - it looks for mod.name
- make sure this is also exported.
.attach
can return connect
and close
functions, which must return promises for starting and stopping the plugin
hook(event, ...args)
Performs Promise.map
listeners defined for event
. All of them are called with the context of the mservice
and args are applied as a spread. This is useful when you want to track custom event hooks completion in the app.
Constructor accepts hooks
Object, which contains of a map of event
to a function
or array of functions
.
They could either be sync or a promise
.
Plugins
Validator plugin
When using this plugin - make sure you npm i ms-validation -S
Attaches ms-validation
instance to your class on ._validator
.
Exposes .validate
and .validateSync
methods on the class itself.
Pass array of absolute and relative paths when creating service to automatically include your schemas.
They will be available under basename of the file. If names collide - last schemas will overwrite existing ones
// MixedData - any variable to be checked
userService.validate('schemaName', MixedData)
.then(mixedData => {
// passed validation
})
.catch(err => {
// validation failed
})
const validationResult = userService.validateSync('schemaName');
if (validationResult.error) {
// validation failed
// handle error
}
// resulting doc if filter: true was set, otherwise original doc
validationResult.doc
Logger plugin
When using this plugin - make sure you npm i bunyan -S
Attaches .log
method, which is an instance of a bunyan
logger.
Provides sane defaults when NODE_ENV
is set to development
.
If not includes ringBuffer trace logger with 100 records.
Can accept either a boolean value or an existing custom bunyan instance;
logger
config
defaultLogger
- when options is set totrue
- will output to stdout, when tofalse
- only to ringBuffer.debug
- when debug is on - default log level isdebug
, otherwise -info
.name
- logger name, will have name ofservice._config.name
ormservice
if not set.streams
- steams config, keys are name of stream, values are stream config
Predefined steams
sentry
logger: {
streams: {
stream: {
dns: 'sentry-dns',
level: 'error',
options: {
// sentry options
},
},
},
}
Example
const userService = new UserService({
logger: {
debug: false,
defaultLogger: true
}
});
// will output data to stdout
userService.log.info('Flying just fine!');
// will only save to ringBuffer stream
userService.log.debug('You won\'t see me!');
AMQP plugin
When using this plugin, make sure you also do npm i ms-amqp-transport -S
Enables AMQP transport makeomatic/ms-amqp-transport
It allows the service to communicate over AMQP protocol. If service.router
plugin is enabled, then we will make the best attempt to setup listeners
and route incoming messages through this plugin. Attaches ._amqp
to service
.
Events are emitted when plugin has completed connecting, or disconnecting. First arg is the transport instance
plugin:connect:amqp
plugin:close:amqp
const userService = new UserService({
amqp: {
transport: {
queue: 'my-nice-queue',
listen: ['users.ping'],
},
router: {
enabled: true
},
}
});
// messages that are sent to users.ping will be processed
RedisCluster plugin
NOTE: you can use only 1 of the plugins for redis - either cluster or sentinel
When using this plugin, make sure you also do npm i ioredis -S
Enables redisCluster communication based on ioredis
module.
Allows one to setup connection to redis and communicate with it;
Events are emitted when plugin has completed connecting, or disconnecting. First arg is the transport instance
plugin:connect:redisCluster
plugin:close:redisCluster
const userService = new UserService({
plugins: [ 'redisCluster' ],
redis: {
hosts: [{
host: '...',
port: Number
}],
options: {
// ...
}
}
});
// any redis command will be applicable
Redis Sentinel plugin
NOTE: you can use only 1 of the plugins for redis - either cluster or sentinel
When using this plugin, make sure you also do npm i ioredis -S
Enables redisCluster communication based on ioredis
module.
Allows one to setup connection to redis and communicate with it in a highly available fashion;
Events are emitted when plugin has completed connecting, or disconnecting. First arg is the transport instance
plugin:connect:redisSentinel
plugin:close:redisSentinel
const userService = new UserService({
plugins: [ 'redisSentinel' ],
redis: {
sentinels: [{
host: '...',
port: Number
}],
name: 'mservice',
options: {
// ...
}
}
});
Elasticsearch plugin
When using this plugin, make sure you also do npm i elasticsearch -S
Enables to use Elasticsearch as a NoSQL storage/search engine. Wraps an official Elasticsearch JavaScript API module.
Events are emitted when plugin has completed connecting, or disconnecting. First arg is the transport instance
plugin:connect:elasticsearch
plugin:close:elasticsearch
const userService = new UserService({
plugins: [ 'elasticsearch' ],
elasticsearch: {
host: 'example.elastic.search:9200',
apiVersion: '2.1',
//...
}
});
Cassandra plugin
When using this plugin, make sure you also do npm i express-cassandra -S
Enables to use Cassandra as a NoSQL storage/search engine. Based on express-cassandra
module.
Events are emitted when plugin has completed connecting, or disconnecting. First arg is the transport instance
plugin:connect:cassandra
plugin:close:cassandra
cassandra = require('express-cassandra');
const service = new Service({
plugins: [ 'cassandra' ],
cassandra: {
service: {
// models also can be path to directory with models
// https://github.com/masumsoft/express-cassandra#write-a-model-named-personmodeljs-inside-models-directory
models: {
Foo: {
fields:{
bar: 'text'
},
key:['bar']
}
}
},
client: {
clientOptions: {
contactPoints: ['cassandra.srv'],
protocolOptions: {
port: 9042
},
keyspace: 'mykeyspace',
queryOptions: {
consistency: cassandra.consistencies.one
}
},
ormOptions: {
defaultReplicationStrategy : {
class: 'SimpleStrategy',
replication_factor: 1
},
dropTableOnSchemaChange: false,
createKeyspace: true
}
}
});
Http plugin
Features
- Allows creating
http
server - Predefined handlers support
Handlers
You can use one of predefined handlers in /src/plugins/http/handlers
directory
Allowed handlers at this moment:
- express (make sure you also do
npm i express -S
) - restify (make sure you also do
npm i restify -S
) - hapi (make sure you also do
npm i hapi -S
, also additional dependencies may be required, for example if you want to use some of hapi's plugins)
Peer dependencies
npm i server-destroy -S
Events
plugin:start:http
plugin:stop:http
Usage
const service = new Service({
plugins: [ 'http' ],
http: {
server: {
attachSocketIO: false, // if true socketio plugin need to be included
handler: 'restify',
handlerConfig: {},
port: 3000,
}
}
});
Hapi features
That's possible to use hapi plugins such as vision
, bell
, etc. All you need is extend the config of http server. Possible options are:
const service = new Service({
plugins: [ 'http' ],
http: {
server: {
handler: 'hapi',
handlerConfig: {
/** implicitly loads 'vision' plugin and decorates a native hapi request with 'sendView' method
* https://github.com/hapijs/vision
*/
views: {
engines: {
hbs: require('handlebars'),
},
paths: 'path/to/templates',
relativeTo: __dirname,
},
plugins: {
list: [{
// you can provide a plugin name, but be sure you've included it in the dependencies
register: 'bell',
options: {
/** bell options */
}
}, {
// also you can provide a function as a plugin
register: require('path/to/custom/plugin'),
options: {
/** options */
}
}, {
// or even just a path to the file
register: 'path/to/custom/plugin',
options: {}
}],
options: {
/** https://hapijs.com/api#plugins */
}
}
},
port: 3000,
}
}
});
// next in route handler you can use a native hapi request instance.
/** file: some/action/handler.js */
module.exports = function actionHandler(request) {
const context = {
example: true,
};
return request.transportRequest.sendView('view', context);
}
// decorates a native hapi request with 'redirect' method.
/** file: redirect/action/handler.js */
module.exports = function redirectHandler(request) {
return request.transportRequest.redirect('https://github.com/makeomatic');
}
Socket.io plugin
Features
Attach Socket.io
instance to .socketIO
property.
Config
router
enabled
-boolean
, enable router, defaultfalse
options
-object
,socket.io
optionsadapter
-object
, adaptername
-string
, adapter name, e.g.amqp
options
-object
, adapter options
Peer dependencies
npm i socket.io -S
npm i ms-socket.io-adapter-amqp -S
Usage
const service = new Service({
plugins: [ 'socketio' ],
socketio: {
router: {
enabled: true,
},
options: {
// socket.io options
},
}
});
// service.socketIO - Socket.io instance
Router plugin
Attach router
to service
that can be used by other plugins