Can a jsreport template call our api to pull data instead of having to push data to it?
I understand that there is the beforeRender event that runs in nodeJS with all templates, how can I have it executed for only one template because the call will be different based on input parameters and context.
yes, you can pull data in a jsreport script. scripts can run globally (for all templates) or just in the scope or just one template, in studio you can choose which scripts should run in the context of your template:
there is an example called Orders that is present in every jsreport installation, this example shows how to call a remote API to pull data to use in the jsreport pipeline.
example Orders scripts (if you are going to try it in your server make sure to allow the http module in your jsreport configuration):
// custom server side script used to fetch data from remote REST API
var http = require('http');
function getOrders(country, cb) {
http.get({
hostname: 'services.odata.org',
port: 80,
path: `/V4/Northwind/Northwind.svc/Orders?$filter=${encodeURI(`ShipCountry eq '${country}'`)}`,
}, (result) => {
var str = '';
result.on('data', (b) => str += b);
result.on('error', cb);
result.on('end', () => cb(null, JSON.parse(str)));
});
}
function beforeRender(req, res, done) {
// the report parameter country can be send from the client API request
req.data.country = req.data.country || 'France'
getOrders(req.data.country, (err, json) => {
if (err) {
return done(err);
}
var orders = json.value;
var ordersByQuarter = {};
orders.forEach((o) => {
o.OrderDate = new Date(o.OrderDate);
var key = o.OrderDate.getFullYear() + '/' + (o.OrderDate.getMonth() + 1);
ordersByQuarter[key] = ordersByQuarter[key] || {
value: 0,
orderDate: o.OrderDate
};
ordersByQuarter[key].value++;
});
req.data.orders = orders;
req.data.accumulatedOrders = ordersByQuarter;
done();
});
}
in this script you can see how we use the getOrders function inside the beforeRender, getOrders gets data from a remote API (using node.js http module) and set the returned data to req.data.orders, which will be used when rendering the template. you can do it in the same way for your case but taking into account any previous input/parameter that you provide, this will help you to prepare your request for the remote API that you want to consume.
Also is there a way to include scripts to the beforeRender so that they simply call our api instead of copy pasting code?
for example you can put the getOrders function in an asset, then in your script import the asset and use the function inside beforeRender function normally. that would help you to avoid repeating code.