seneca-triggers
v1.0.6
Published
Triggers on seneca actions
Downloads
3
Maintainers
Readme
A seneca.js triggers plugin.
seneca-triggers
Last update: 06/06/2018
This module is a plugin for the Seneca framework. It provides before and after triggers management for any action.
Why this plugin?
Thanks to the Seneca framework, which already provides a full action pattern override technique: priors. Seneca plugins are fundamentally just a list of action patterns, and patterns are extensibles. Then, your application can override patterns with its own functionalities.
This plugin makes things easier. You simply declare the triggers objects. Each trigger is intended to fire an action before and/or after the prior action. Then, you implement these before/after actions with their pattern in the target microservices. Done!
Benefits
Logic included
All the logic of the triggers is included in this plugin. Just set it up.
Process control
- The before action must succeed, otherwise the process is stopped. The prior action is not fired and the before action result is returned. With this feature you can:
- prevent invalid transactions
- enforce complex security authorizations
- The prior action must succeed, otherwise the process is stopped. The optional after trigger is not fired. The prior action result is returned.
Retrieving results
- The before action returns a result which can be retrieved by the prior action.
- The prior action returns a result which can be retrieved by the after action.
- The end result can include the before and/or after results in addition to the prior result.
Enjoy it!
Use case: entities
Almost all database engines offer trigerring capabilities. Similarly, you can implement this feature with Seneca entities. And then:
- automatically generate derived column values
- enforce referential integrity across nodes in a distributed environment
- enforce complex business rules
- provide transparent event logging
- provide sophisticated auditing
- maintain synchronous table replicates
- gather statistics on table access
- prevent invalid transactions
- enforce complex security authorizations
- ...
... and all the rest: we know that your imagination has no limit :)
How it works
Plugin declaration
Your application must declare this plugin use:
seneca.use('seneca-triggers', {
[ ... triggers array ... ]
})
The triggers array contains a list of Trigger objects.
/!\ Caution: the triggers order is significant! As this plugin use pattern overrides, please remember: in the same way that the order of plugin definition is significant, the order of pattern overrides is also significant.
Trigger object
The pattern is:
{
pattern: 'role:the_prior_role,cmd:the_prior_command, ...',
resultname: 'prior_name',
before: {
pattern: 'role:the_before_role,cmd:the_before_command, ...',
options: {
aName: aValue,
...
},
resultname: 'my_before_name'
},
after: {
pattern: 'role:the_after_role,cmd:the_after_command, ...',
options: {
aName: aValue,
...
},
resultname: 'my_after_name'
},
}
- pattern: the prior pattern to be overriden.
- resultname: the name of the field containing the prior result in the out prior message. See the Prior result chapter below.
- before: this field is optional. It contains the before trigger properties. See below.
- after: this field is optional. It contains the after trigger properties. See below.
Trigger properties
The pattern is:
{
pattern: 'role:the_trigger_role,cmd:the_trigger_command,...',
options: {
aName: aValue,
...
},
resultname: 'my_trigger_name'
}
- pattern: the pattern of the action that will be fired.
- options: this field is optional. If the trigger action needs additional data, they are declared in this object. This options object will be passed in the trigger action message.
- resultname: this field is optional. If set, this trigger result is to be included in the end result. The trigger result key name in the end result object is this resultname value.
Applying triggers
After declaring triggers, they must be applied to benefit of the override feature. Please use this code in your main script:
/* Please put your seneca.add() statements before these line. */
/* Applies triggers */
seneca.act({role: 'triggers', cmd: 'apply'}, (err, reply) => {
if (err) { ... }
/* Please put your main code here. */
})
/* Application end: seneca.close(...) */
This code must be inserted immediatly after all your seneca.add()
statements. Remember: the pattern override order is significant.
The main code of your script, including its own seneca.act ()
statements, must be inserted into the triggers seneca.act
function as shown.
Before trigger result
It's the responsability of the before
trigger to return a result with at least the property:
{success: true/false}
Otherwise, the success: true
value is used by default.
If success is false, the override process stops. The prior action is not fired. The end result is the before trigger result plus the property:
trigger: { ... the before trigger object ... }
Prior message
The prior message is always transmitted to the trigger action.
The trigger action function can use args
retrieved from the prior message.
If your trigger action need additional data, it can be set in the trigger options configuration:
options: {
aName: aValue,
...
}
Prior result
It's the responsability of the prior action to return a result with at least the property:
{success: true/false}
Otherwise, the success: true
value is used by default.
If success is false, the override process stops. The optional after action is not fired. The end result is the prior result.
If succeed, the prior action result is passed as argument in the args
array of the after trigger message. So the after action can eventually retrieve and use it.
This argument name is set in the trigger configuration, in the main field resultname
.
And then...
That's all. Enjoy it!
The 'hello World' example
This (very) simple test shows the interaction between a before trigger, an after trigger and the prior action:
- If the before trigger is set, the output and the result of the prior action changes.
- If the after trigger is set, its action output displays the prior action result.
Configuration
Here is the triggers configuration for this test:
config.triggers = [
{
pattern: 'role:test,cmd:helloworld',
resultname: 'priorResult',
before: {
pattern: 'role:test,cmd:setname',
options: {
name: 'Jack'
},
resultname: 'Set name'
},
after: {
pattern: 'role:test,cmd:question',
options: {
question: 'How are you?'
}
}
}
]
The before trigger adds its result to the end result, with the key Set name
.
The after trigger leaves the end result unchanged.
Actions
The prior action
Declaration:
seneca.add({role: 'test', cmd: 'helloworld'}, helloWorld)
Action:
function helloWorld (args, done) {
var name = args['Set name'] ? args['Set name'].name : 'World'
var text = 'Hello ' + name + '!'
console.log(text)
done(null, {msg: text})
}
As usual, its output is:
Hello World!
The before trigger
Declaration:
seneca.add({role: 'test', cmd: 'setname'}, setName)
Action:
function setName (args, done) {
console.log('> First of all, my name is ' + args.name + '.')
done(null, {name: args.name})
}
The trigger configuration contains a name
property. For example: name: 'Jack'
. Depending on this property, its output is:
> First of all, my name is Jack.
Then, the name value is passed as argument to the prior message. The prior action retrieves this name value. The prior output changes accordingly:
Hello Jack!
The after trigger
Declaration:
seneca.add({role: 'test', cmd: 'question'}, question)
Action:
function question (args, done) {
console.log('# You said: "' + args.priorResult.msg + '".')
console.log('# ' + args.question)
done(null, {question: args.question})
}
As set, the prior result has been saved in the priorResult
argument. Depending on this argument, the trigger output is:
# You said: "Hello World!".
# How are you?
And if the before trigger is also set, it becomes:
# You said: "Hello Jack!".
# How are you?
The end result
The prior end result is:
{"msg":"Hello World!"}
If the before trigger is set, the end result changes:
{"msg":"Hello Jack!","Set name":{"name":"Jack"}}
Run the tests
The test
directory contains the full hello World sources. The 6 scenarios can be tested:
- no trigger
- before trigger only
- before trigger with bad result
- after trigger only
- before and after triggers
- before and after triggers with prior bad result
The outputs can be checked here.
To run these tests:
npm test
Install
To install, simply use npm:
npm install seneca-triggers
Test
To run tests, simply use npm:
npm test
Contributing
The Senecajs org encourages open participation. If you feel you can help in any way, be it with documentation, examples, extra testing, or new features please get in touch.
License
Copyright (c) 2017, Richard Rodger and other contributors. Licensed under MIT.