Library to execute JSON task with declarative programming. It converts a JSON collection into a list of actions (asynchronous or not), executes them and returns the result. It also efficiently manages possible errors.
The next example JSON declares 5 actions that manage an ajax request to get the data of a user's shopping cart. This task returns the products of the cart and the total price, or a 500 http error if there is a problem.
microTasks.taskRun([
{
// get from mysql db the user id
// and set it in 'payload.userId'
method: 'mysql.query',
params: {
query: 'SELECT id FROM users WHERE email="{{payload.email}}"',
handler: 'field'
},
resultPath: 'userId'
},
{
// get from mysql db the units and prices of the product of the cart of this user
// and set it in 'payload.cartProducts' as array
method: 'mysql.query',
params: {
query: 'SELECT units, price FROM cart WHERE userId={{payload.userId}}',
handler: 'rows'
},
resultPath: 'cartProducts'
},
{
// map 'payload.cartProducts' multiplying units by price and set the result in totalByProduct property
// and set it in 'payload.cartProducts'
method: 'collection.mapByIterator',
params: ['{payload.cartProducts}', 'math.multiply', 'totalByProduct', 'units', 'price'],
resultPath: 'cartProducts'
},
{
// reduce 'payload.cartProducts' adding totalByProduct
// and set it in 'cartTotalPrice'
method: 'collection.reduce',
params: ['math.add', 'totalByProduct'],
resultPath: 'cartTotalPrice'
},
{
// response the ajax request with cartProducts, cartTotalPrice and status code
method: 'request.response',
params: {
status: 200,
cartTotalPrice: '{payload.cartTotalPrice}',
cartProducts: '{payload.cartProducts}'
}
},
{
// response the ajax request with error
catch: true,
method: 'request.response',
params: {
status: 500,
error: 'Internal error'
}
}
], {
email: '[email protected]'
})
Each action becomes a promise. Unknown errors can be managed with catch property.
The previous example would become something like:
const payload = {}
new Promise((resolve) => resolve())
.then(() => {
return mysqlConnect()
})
.then(() => {
return mysqlQuery('SELECT id FROM users WHERE email="[email protected]"')
})
.then((userId) => {
payload.userId = userId
})
.then(() => {
return mysqlQuery('SELECT units, price FROM cart WHERE userId=123')
})
.then((cartProducts) => {
payload.cartProducts = cartProducts
})
.then(() => {
payload.cartProducts = payload.cartProducts.map((cartProduct) => {
cartProduct.totalByProduct = cartProduct.units * cartProduct.price
return cartProduct
})
})
.then(() => {
payload.cartTotalPrice = payload.cartProducts.reduce((total, cartProduct) => {
total += cartProduct.totalByProduct
}, 0)
})
.then(() => {
request.send({ cartTotalPrice: payload.cartTotalPrice, cartProducts: payload.cartProducts }).status(200)
})
.catch(() => {
request.send({ error: 'Internal error' }).status(500)
})
- Task: it is an ordered list of actions, I mean, an array of objects.
- Action: define the execution of an action with a method, parameters and a property to set the return of the method. I mean, a plain object. An action can have a list of actions inside that, and then can be executed in series, parallel or in race. You can also define conditional actions. With these options you can create any flow of actions. For more info see action configuration. This is an example:
microTasks.taskRun([
{
method: 'mysql.query',
params: { query: 'SELECT units, price FROM cart WHERE userId={{payload.userId}}' },
resultPath: 'cartProducts'
}
])
- Method: defines a method that can be executed from an action.
microTasks.methodRegister('mysql.query', (data) => {
return new Promise((resolve, reject) => {
// connect
const connection = mysql.createConnection(data.connection)
connection.connect()
// query
connection.query(data.query, (err, results) => {
if (err) {
reject(err)
} else {
resolve(results)
}
})
})
})
- Payload: object shared among all actions in a task.
To access a property of the payload from an action param, you can use
'{payload.user.id}'
to get the value or'The user id is {{payload.user.id}}'
to parse a string. See action parser for more info. - Context: object shared among all tasks, is the application context.
Useful for saving global configuration, task status...
To access a property of the context you can use
'{context.mysql.connection.host}'
to get the value or'The db connection host is {{context.mysql.connection.host}}'
to parse a string. See action parser. - Hooks: to intercept the flow of tasks and actions you can register and listen hooks. See registered hooks. (What is a hook?)
To facilitate the debugging of tasks, each action logs:
- input parameters and parsed input parameters
- method result
- final status of the action:
checking condition
>solving
>solved
,ignored
,error
orrejected
- captured errors
- the execution time
This action logs next data (example):
microTasks.taskRun([{
if: {
method: 'conditionalAction',
params: '{payload.myCondition}',
equalTo: true
},
method: 'print',
params: 'This action is executed because conditionalAction is ok'
}], {
myCondition: true
})
/*
{
if: {
method: "conditionalAction",
params: "{payload.myCondition}",
parsedParams: [true],
equalTo: true,
resultValue: true
},
method: "print",
params: "This action is executed because conditionalAction is ok",
parsedParams: ["This action is executed because conditionalAction is ok"],
status: "solved",
time: {
start: 1511375841559,
end: 1511375841576,
duration: 17
}
}
*/
We recommend you read the basic concepts, see a couple of examples and then read the documentation:
We have created the following libraries with the methods and actions most used in projects. To use the libraries you just have to import them in your application.
- Hello world
- Async action
- Conditional action
- Rejected action
- Payload
- Context
- Serial actions
- Parallel actions
- Race actions
- Result path
- Debug log
- Task time
npm install
npm start # run examples/hello-world.js
npm run devtool # run examples/hello-world.js with devtool
npm run lint
npm run docs