Why rewire not inject mock for testing in nodejs? - node.js

I'm trying to inject a mock for testing using mocha. But it looks like the mock is not picked up and the test still uses the real data from server. I'm trying to get the data from foursquare.
Here's my code.
var foursquare = require('foursquarevenues'),
Promise = require('promise'),
_ = require('underscore');
var Foursquare = function(client_id, client_secret) {
this.the_4sqr_lib = foursquare(client_id, client_secret);
};
Foursquare.prototype.getVenue = function(id) {
var self = this;
return new Promise(function(resolve, reject) {
self.the_4sqr_lib.getVenue({'venue_id' : id}, function(error, response) {
if(error) {
reject(error);
}
var venueData = response.response.venue;
var firstPhoto = venueData.photos.groups[0].items[0];
var theVenue = {
id: venueData.id,
name: venueData.name,
photo: firstPhoto.prefix + firstPhoto.width + 'x' + firstPhoto.height + firstPhoto.suffix,
url: venueData.canonicalUrl
};
resolve(theVenue);
});
});
};
module.exports = Foursquare;
And here's my test
var rewire = require("rewire"),
Foursquare = rewire('../../lib/foursquare.js');
var client_id, client_secret, foursquare;
beforeEach(function() {
client_id = process.env.FOURSQUARE_CLIENT_ID;
client_secret = process.env.FOURSQUARE_CLIENT_SECRET;
foursquare = new Foursquare(client_id, client_secret);
});
it('should get venue without photo', function(done) {
var mockFoursquare = {
getVenue : function(id, cb) {
var response = {
response : {
response : {
venue : {
photos : {
count:0,
groups : []
}
}
}
}
}
cb(null, response);
}
};
Foursquare.__set__('foursquarevenues', mockFoursquare);
var venue = foursquare.getVenue('430d0a00f964a5203e271fe3');
venue.then(function(venue) {
venue.id.should.equal('');
venue.name.should.equal('');
venue.photo.should.equal('');
venue.url.should.equal('');
done();
}).catch(done);
});
I'm expecting the test to fail because of undefined but it's still getting the real data.

I had the same problem when using var self = this;. The methods called like self.someMethod() didn't get mocked.
I've partially solved it by assigning the mock without rewire:
MyModule = rewire('../lib/MyModule');
MyModule.__set__({"someMethodNotUsingSelf": function(){...}});
MyModule.someMethodThatUsesSelf = function() { //some mock code };
someValue.should.equal('something');
//...
Hope it helps!

Related

Lambda NodeJS works intermittent with async method

I have a lambda function written in node.js. The lambda logic is to extract secrets from aws secret manager and pass the params to another module with a token to make a soap call.This lambda was working as expected without async method to get secreats when secreats hardcoded.
But after adding an async getsecrets method the lambda works intermittently while testing in aws console. The getsecreats returns params every time. But the lambda terminates without the intended output. It doesn't make any soap call.
The logic of the lambda code is
Get the secret
Pass the secret to the CallServicewithToken()
get XML data from soap and populate it into the database.
Why it works intermittently when introducing async calls? I have tried introducing async to all methods. still the same issue. Appreciate any input/help.
The code is as below
'use strict';
var soap = require('strong-soap').soap;
const aws = require("aws-sdk");
const request = require('request');
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0;
var rfcUrl = process.env.rfcser_url;
var testUrl = process.env.faccser_url;
var region = process.env.region;
var secretName = process.env.secretName;
var oauthurl = process.env.oauthurl;
var rfcRequestArgs;
var parsedResult;
var tokenrequest;
exports.handler = async function(event, context,callback) {
const secret = await getSecrets();
CallServicewithToken();
};
async function getSecrets() {
const config = { region : region, apiVersion: 'latest' };
let secretManager = new aws.SecretsManager(config);
const Result = await secretManager.getSecretValue({ SecretId: secretName }).promise();
parsedResult = JSON.parse(Result.SecretString);
tokenrequest = {
url: oauthurl,
form: {
client_id: parsedResult.client_id,
client_secret: parsedResult.client_secret,
grant_type:'client_credentials',
scope:parsedResult.scope
}
};
console.log('client_id: ' + parsedResult.client_id);
console.log('client_secret: ' + parsedResult.client_secret);
console.log('testservice_userid: ' + parsedResult.testservice_userid);
}
function CallServicewithToken() {
console.log('Calling CallServicewithToken ');
request.post(tokenrequest, (err, res, body) => {
if (err) {
console.log(' error2: ' + err);
return;
}
rfcRequestArgs = {
UserName: parsedResult.service_username
};
var tokenobj = JSON.parse(body);
var token = 'Bearer '+ tokenobj.access_token;
var credentials = {
Authorization:{
AuthToken: token
}
}
var options = {};
console.log('Calling Service.');
soap.createClient(rfcUrl, options, function(err, client) {
client.addSoapHeader(
`<aut:Authorization xmlns:aut="http://soap.xyznet.net">
<aut:AuthToken>${token}</aut:AuthToken>
</aut:Authorization>`
);
var method = client['GetSourceLocationData'];
method(RequestArgs, function(err, result, envelope, soapHeader) {
if (err) {
console.log('error3: ' + err);
return;
}
else
{
console.log('Received response from GetSourceLocationData().');
CallTESTService(JSON.stringify(result));
}
});
function CallTESTService(LocData)
{
var testRequestArgs = {
UserID: parsedResult.testservice_userid,
AuthorizationKey: parsedResult.testservice_authorizationkey,
LocationData: LocData
};
console.log('Calling test Service.');
options = {};
soap.createClient(testUrl, options, function(err, client) {
client.addSoapHeader(
`<Authorization xmlns="testWebService">
<AuthToken>${token}</AuthToken>
</Authorization>`
);
var test_method = client['UpdateLocationData'];
console.log('Called UpdateLocationData service method.');
test_method(testRequestArgs, function(err, result, envelope, soapHeader) {
if(err) {
console.log('test error: ' + err);
return;
}
else
{
console.log('Response: \n' + JSON.stringify(result));
console.log('Data updated through test service method.');
}
});
});
}
});
});
}

Not able to mock S3 download request using proxyquire

const awsSdk = require('aws-sdk');
module.exports = {
downloadFile(bucketName, fileName, callback) {
var s3 = new awsSdk.S3();
var params = { Bucket: bucketName, Key: fileName };
var file = require('fs').createWriteStream('abcd.jpg');
var stream = s3.getObject(params).on('error', function (err) {
console.log(' download.on');
callback('error', null);
})
.createReadStream()
stream.pipe(file);
}
}
Above, is the code i need to mock in my Test class using proxyquire. The issue is, im not able to mock methods like getObject,on,createReadStream. Also after mocking i need to emit the error event from test class that will trigger the above on method which will call the callback in my test class where exception is tested.
Below is my test class code.
const proxyquire = require('proxyquire').noCallThru().noPreserveCache();
const sinon = require('sinon');
const emitter = require('events').EventEmitter;
function Download() {
emitter.call(this);
this.error = function () {
this.emit('error');
}
}
describe('S3 download test', () => {
awsSdkMock = {}
awsSdkMock.config = {};
awsSdkMock.config.region = { };
var s3Instance = {};
awsSdkMock.S3 = function (){
return s3Instance;
};
var object = {};
s3Instance.getObject = function (params){
return object;
};
var request = {};
const errorCallBack = sinon.spy();
var err = 'error';
object.on = function (err, errorCallBack) {
console.log('object.on');
errorCallBack();
return request;
};
var stream = {};
request.createReadStream = function(){
console.log('createReadStream');
return stream
};
stream.pipe = function(file){
console.log('download.error');
// download.error();
};
Download.prototype.__proto__ = emitter.prototype;
var download = new Download();
const s3 = proxyquire('./../../../modules/s3', {
'aws-sdk': awsSdkMock
})
it('Error in download test', (done) => {
const errorCallBack = sinon.spy();
s3.downloadFile('123', 'abcd', errorCallBack);
sinon.assert.calledWith(errorCallBack, 'error', null);
done();
});
})
Any help is appreciated.

I am having issues with exporting in node

I am trying to make an api endpoint for data coming from dynamoDB. I believe that I have everything connected but when I run postman to check the api (api/db) it doesn't recognize the functions from the db.js in the db.js (for routes). I have run a test on api/test and am getting the information back. Here is the code from both files:
1. This scans the database and I'm trying to export it to another file.
var AWS = require('aws-sdk');
var params = {
TableName : "iotbuttonsn",
//KeyConditionExpression: "serialNumber =:serialNumber",
//ExpressionAttributeValues: {
// ":serialNumber":"*"
//},
ScanIndexForward: false,
Limit: 3,
Select: 'ALL_ATTRIBUTES'
};
AWS.config.update({
region: "us-east-1",
endpoint: "https://dynamodb.us-east-1.amazonaws.com"
});
var docClient = new AWS.DynamoDB.DocumentClient();
var getDatabase = (function(){
return {
scanDB: function(){
docClient.scan(params, onScan);
var onScan = function(err, data){
if (err) {
console.log(err.message);
} else {
console.log('scan success');
len = data.Items.length;
for (n=0; n<len; n++) {
clickTypes[n] = data.Items[n].payload.clickType;
serialNums[n] = data.Items[n].serialNumber;
}
}
};
},
clickTypes: [],
serialNums: []
};
})();
module.exports = getDatabase;
2. This is where I'm trying to input but db.scanDB() isn't working:
var router = require('express').Router();
var db = require('../routes/db.js');
router.get('/', function(req, res){
db.scanDB();
buttons =
[
iot_buttonOne = {
serialNum: db.serialNum[0],
clickType: db.clickTypes[0]
},
iot_buttonTwo = {
serialNum: db.serialNum[1],
clickType: db.clickTypes[1]
}
]
.then(
function scanSuccess(data){
res.json(data);
},
function scanError(err){
res.send(500, err.message);
}
);
});
module.exports = router;
Change your db.scan() function to properly return an asynchronous result:
// db.js
module.exports = {
scanDB: function(cb){
docClient.scan(params, function(err, data) {
var clickTypes = [], serialNums = [];
if (err) {
console.log(err.message);
cb(err);
} else {
console.log('scan success');
len = data.Items.length;
for (n=0; n<len; n++) {
clickTypes[n] = data.Items[n].payload.clickType;
serialNums[n] = data.Items[n].serialNumber;
}
cb(null, {clickTypes, serialNums});
}
});
}
};
Then, when you use it:
var db = require('../routes/db.js');
db.scanDB(function(err, data) {
if (!err) {
// data.clickTypes
// data.serialNums
} else {
// process error
}
});
It really does not good to put the scanDB result on the DB object the way you were doing because there was no way for the caller to know when the asynchronous operation was done. So, since you have to provide some notification for the caller when the async operation is done (either via callback or promise), you may as well just pass the results there too.
Also, the .then() handler in your router.get(...) handler does not belong there. I don't know why it's there at all as there are no promises involved in the code you show. Perhaps a cut/paste error when creating the question?
Note, I removed the IIFE from your getDatabase() definition since there was no benefit to it other than a little more complicated code.

stub nodejs promise in chain to return error

I'm new to using promises in nodejs and also in testing them. I have managed to test the individual modules separately, but when it comes to testing the chain of promises, I am having some trouble. I tried following the examples found here and on the npm page for sinon-as-promised but don't seem to managed to control the flow and trigger the error in the first promise of the chain.
I am using mocha, chai and sinon for my tests with sinon-as-promised and chai-as-promised.
I am trying to test this module:
'use strict';
var mySQS = require('./modules/sqs/sqs-manager');
var sWebHook = require('./modules/webhooks/shopify/webhooks');
var main = {};
main.manageShopifyWebhook = function (params, callback) {
sWebHook.verify(params.srcHmac, params.rawBody, params.shopName.split('.myshopify.com')[0], params.productId)
.then(function(data) {
var body = {
"params": {
"productId": data.productId,
"shopName": data.shopName
},
"job": "call-update-item"
};
mySQS.create_Queue(body)
.then(mySQS.send_Message)
.then(function(result) {
callback(null, result);
})
.catch(function(error) {
callback(error, null);
});
});
};
module.exports = main;
This is the sWebHook module I want to trigger the reject callback in the main flow:
'use strict';
var crypto = require('crypto');
var nconf = require('../../../../config/nconfig');
var webHookManager = {};
webHookManager.verify = function (srcHmac, rawBody, shopName, productId) {
return new Promise(function (resolve, reject) {
rawBody = new Buffer(rawBody, 'base64');
var sharedSecret = nconf.get('SHOPIFY_CLIENT_SECRET');
var digest = crypto.createHmac('SHA256', sharedSecret).update(rawBody).digest('base64');
console.log('***** CALCULATED DIGEST *****');
console.log(digest);
console.log('***** HMAC FROM SHOPIFY *****');
console.log(srcHmac);
if (digest !== srcHmac) {
console.log('Hello');
var customError = new Error('Unauthorized: HMAC Not Verified');
reject(customError);
return false;
}
var newEvent = {
shopName: shopName,
productId: productId
};
console.log('!! WEBHOOK VERIFIED !!');
resolve(newEvent);
});
};
module.exports = webHookManager;
And these are my tests so far (which do not work):
'use strict';
var chai = require('chai');
var sinonChai = require("sinon-chai");
var expect = chai.expect;
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
var sinon = require('sinon');
chai.use(sinonChai);
var proxyquire = require('proxyquire').noCallThru();
var AWS = require('mock-aws');
describe('MAIN', function() {
require('sinon-as-promised');
var testedModule,
sWebHookStub,
sqsQueueStub,
sqsSendMsgStub,
callbackSpy,
fakeDataObj;
before(function() {
sWebHookStub = sinon.stub();
sqsQueueStub = sinon.stub();
sqsSendMsgStub = sinon.stub();
callbackSpy = sinon.spy();
fakeDataObj = {
srcHmac: '12345',
rawBody: 'helloworld',
shopName: 'mario-test.myshopify.com',
productId: '6789'
};
testedModule = proxyquire('../lib/main', {
'./modules/webhooks/shopify/webhooks': {
'verify': sWebHookStub
},
'./modules/sqs/sqs-manager': {
'create_Queue': sqsQueueStub,
'send_Message': sqsSendMsgStub
}
});
});
it('calling shopifyVeriWebhook returns an error', function() {
var fakeError = new Error('Error verifying webhook');
sWebHookStub.rejects(fakeError);
testedModule.manageShopifyWebhook(fakeDataObj, function() {
callbackSpy.apply(null, arguments);
});
expect(callbackSpy).has.been.called.and.calledWith(fakeError, null);
});
});
So, I ended up figuring out how to test chains of promises using sinon. For the following main module (Note: the other modules all return promises):
'use strict';
var mySQS = require('./modules/sqs/sqs-manager');
var sWebHook = require('./modules/webhooks/shopify/webhooks');
var main = {};
//#params {object} params
//#params {string} params.srcHmac
//#params {string} params.rawBody
//#params {string} params.shopName - <shop-name.myshopify.com>
//#params {string} params.productId
main.manageShopifyWebhook = function (params) {
return new Promise(function(resolve, reject) {
sWebHook.verify(params.srcHmac, params.rawBody, params.shopName.split('.myshopify.com')[0], params.productId)
.then(function(data) {
var body = {
"params": {
"productId": data.productId,
"shopName": data.shopName
},
"job": "call-update-item"
};
return mySQS.create_Queue(body);
})
.then(mySQS.send_Message)
.then(resolve)
.catch(function(err) {
reject(err);
});
});
};
module.exports = main;
The secret is to manually resolve or reject the promises and write the expectation within the callback functions of the then or catch methods (just as we would do if we were writing tests for async code using done). And we then trigger the method we want to test, saving its value to a variable. Like so:
'use strict';
var chai = require('chai');
var sinonChai = require("sinon-chai");
var expect = chai.expect;
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);
require('sinon-as-promised');
var sinon = require('sinon');
chai.use(sinonChai);
var proxyquire = require('proxyquire').noCallThru();
describe('MAIN', function() {
require('sinon-as-promised');
var testedModule,
sWebHookStub,
sqsQueueStub,
sqsSendMsgStub,
callbackSpy,
fakeDataObj;
before(function() {
sWebHookStub = sinon.stub();
sqsQueueStub = sinon.stub();
sqsSendMsgStub = sinon.stub();
callbackSpy = sinon.spy();
fakeDataObj = {
srcHmac: '12345',
rawBody: 'helloworld',
shopName: 'mario-test.myshopify.com',
productId: '6789'
};
testedModule = proxyquire('../lib/main', {
'./modules/webhooks/shopify/webhooks': {
'verify': sWebHookStub
},
'./modules/sqs/sqs-manager': {
'create_Queue': sqsQueueStub,
'send_Message': sqsSendMsgStub
}
});
});
it('calling shopifyVeriWebhook returns an error when trying to VERIFY WEBHOOK', function() {
var fakeError = new Error('Error verifying webhook');
sWebHookStub.rejects(fakeError)().catch(function(error) {
expect(shopifyWebhook).to.eventually.equal(error);
});
var shopifyWebhook = testedModule.manageShopifyWebhook(fakeDataObj);
});
it('calling shopifyVeriWebhook returns an error when trying to CREATE SQS QUEUE', function() {
var fakeBody = {
"params": {
"productId": '1234',
"shopName": 'name'
},
"job": "call-update-item"
};
var fakeError = new Error('Error creating sqs queue');
sWebHookStub.resolves(fakeBody)().then(function(result) {
sqsQueueStub.rejects(fakeError)().catch(function(error) {
expect(shopifyWebhook).to.eventually.equal(error);
});
});
var shopifyWebhook = testedModule.manageShopifyWebhook(fakeDataObj);
});
it('calling shopifyVeriWebhook returns an error when trying to SEND SQS MESSAGE', function() {
var fakeData = {
queueUrl: '5678',
payLoad: '{"message": "Hello World"'
};
var fakeBody = {
"params": {
"productId": '1234',
"shopName": 'name'
},
"job": "call-update-item"
};
var fakeError = new Error('Error sending sqs message');
sWebHookStub.resolves(fakeBody)().then(function(result) {
sqsQueueStub.resolves(fakeData)().then(function(result) {
sqsSendMsgStub.rejects(fakeError)().catch(function(error) {
expect(shopifyWebhook).to.eventually.equal(error);
});
});
});
var shopifyWebhook = testedModule.manageShopifyWebhook(fakeDataObj);
});
it('calling shopifyVeriWebhook is SUCCESSFUL', function() {
var fakeData = {
queueUrl: '5678',
payLoad: '{"message": "Hello World"'
};
var fakeBody = {
"params": {
"productId": '1234',
"shopName": 'name'
},
"job": "call-update-item"
};
var fakeResponse = {
'message': 'success'
};
sWebHookStub.resolves(fakeBody)().then(function(result) {
sqsQueueStub.resolves(fakeData)().then(function(result) {
sqsSendMsgStub.resolves(fakeResponse)().then(function(result) {
expect(shopifyWebhook).to.eventually.equal(result);
});
});
});
var shopifyWebhook = testedModule.manageShopifyWebhook(fakeDataObj);
});
});
Bonus sample - I needed to run my code on aws lambda, and therefore needed to have a final callback. So I had the main entry point to my code in a file called lambda.js:
'use strict';
var main = require('./lib/main');
//Verifies shopify webhooks
//#params {object} event
//#params {string} event.srcHmac
//#params {string} event.rawBody
//#params {string} event.shopName - <shop-name.myshopify.com>
//#params {string} event.productId
exports.shopifyVerifyWebHook = function (event, context, callback) {
console.log('---- EVENT ----');
console.log(event);
main.manageShopifyWebhook(event)
.then(function(result) {
callback(null, result);
})
.catch(function(err) {
callback(err, null);
});
};
And for this I needed to control the result of the promises and make sure the callback was called with either an error or a success message.
The premiss is the same.
describe('LAMBDA', function() {
var testedModule,
mainShopStub,
callbackSpy,
mainModule,
fakeEvent;
before(function() {
callbackSpy = sinon.spy();
fakeEvent = {
srcHmac: '12345',
rawBody: 'helloworld',
shopName: 'mario-test.myshopify.com',
productId: '6789'
};
testedModule = require('../lambda');
mainModule = require('../lib/main');
mainShopStub = sinon.stub(mainModule, 'manageShopifyWebhook');
});
after(function() {
mainShopStub.restore();
});
it('calling shopifyVerifyWebHook returns an error', function() {
var fakeError = new Error('Error running lambda');
mainShopStub.rejects(fakeError);
mainShopStub().catch(function (error) {
expect(callbackSpy).has.been.called.and.calledWith(error, null);
});
testedModule.shopifyVerifyWebHook(fakeEvent, {}, function() {
callbackSpy.apply(null, arguments);
});
});
it('calling shopifyVerifyWebHook return a data object', function() {
var fakeObj = {message: 'success'};
mainShopStub.resolves(fakeObj);
mainShopStub().then(function (result) {
expect(callbackSpy).has.been.called.and.calledWith(null, result);
});
testedModule.shopifyVerifyWebHook(fakeEvent, {}, function() {
expected.resolves(fakeObj);
callbackSpy.apply(null, arguments);
});
});
});
Before getting into how to test multiple promises and validating errors, there is a much larger problem with your code.
manageShopifyWebhook() is constructed using an anti-pattern of promises which is, you're using a callback structure to return your promise value instead of returning your promise directly. If you do this, you're taking away a large benefit of promises, direct chain for error handling. Furthermore, you won't be able to use sinon-as-promised and chai-as-promised since they expect a Promise/thenable to be returned.
However, this is a rather quick fix in your code, by simply returning the promise created by sWebHook.verify():
main.manageShopifyWebhook = function (params) {
// Return the promise directly
// the final return will be returned to the original caller of manageShopifyWebhook
return sWebHook.verify(params.srcHmac, params.rawBody, params.shopName.split('.myshopify.com')[0], params.productId)
.then(function(data) {
var body = {
"params": {
"productId": data.productId,
"shopName": data.shopName
},
"job": "call-update-item"
};
return mySQS.create_Queue(body);
})
.then(mySQS.send_Message)
.then(function(result) {
return result;
})
.catch(function(err) {
// In reality you can let error propagate out here
// if you don't need to do anything special with it and let
// the promise just return the error directly
// I've only done this so we can return 'Error Verifying Webhook' as an error from the promise returned by manageShopifyWebhook()
return Promise.reject(new Error('Error verifying webook'));
});
});
};
Now that manageShopfiyWebhook() is returning a promise, you can use the two as-promised test libraries.
For chai-as-promised you need to convert your expect() to look for a promise using the chain eventually and then you can use rejectedWith() to validate the Error/Error Message.
To validate multiple promises tests you can use Promise.all() and pass in all your promise returning assertions and return the outcome of Promise.all() to your mocha it().
I don't use sinon but the above should've given you enough direction to figure out how to use this pattern with sinon-as-promised as well since it will work for any Promise returning testing library.
it('calling shopifyVeriWebhook returns an error', function() {
var fakeError = new Error('Error verifying webhook');
let shopifyWebhook = testedModule.manageShopifyWebhook(fakeDataObj);
return Promise.all([
expect(shopifyWebhook).to.eventually.be.rejectedWith(fakeError);
]);
});

Sails.js - How do I reuse (most) of this code across multiple controller actions?

I'm grabbing feeds using a particular npm module and what I want to do is create multiple actions with the same code although I don't want to repeat the whole code. Here's my controller:
module.exports = {
buzzy: function (req, res) {
var FeedParser = require('feedparser'),
request = require('request');
var req = request('http://rss.nytimes.com/services/xml/rss/nyt/Technology.xml'),
feedparser = new FeedParser();
req.on('error', function (error) {
// handle any request errors
});
req.on('response', function (res) {
var stream = this;
if (res.statusCode != 200) return this.emit('error', new Error('Bad status code'));
stream.pipe(feedparser);
});
feedparser.on('error', function (error) {
// always handle errors
});
feedparser.on('readable', function () {
// This is where the action is!
var stream = this,
meta = this.meta // **NOTE** the "meta" is always available in the context of the feedparser instance
,
item;
while (item = stream.read()) {
var newData = item;
Buzzfeed.create({'title': newData.title, 'url': newData.link, 'source': 'nytimesTech', 'category': 'tech'}, function (err, newTitles) {
});
}
});
}
};
so similar to the 'buzzy' controller action, I want to create multiple actions - following are the lines that are going to be unique in each controller
var req = request('http://rss.nytimes.com/services/xml/rss/nyt/Technology.xml'),
and
Buzzfeed.create({'title': newData.title, 'url': newData.link, 'source': 'nytimesTech', 'category': 'tech'}, function (err, newTitles) {
});
Curious, what would be the best approach to implement this so I'm not repeating?
You can use Services. If you have functions that are being used at multiple places in the code, you can use them.
See the documentation here: Services
In the /api/services folder, create a file, name it BuzzyAPI.js (say), and add the following code:
var FeedParser = require('feedparser'),
request = require('request');
module.exports = {
buzzy: function (reqUrl) {
var req = request(reqUrl),
feedparser = new FeedParser();
req.on('error', function (error) {
});
req.on('response', function (res) {
var stream = this;
if (res.statusCode != 200) return this.emit('error', new Error('Bad status code'));
stream.pipe(feedparser);
});
feedparser.on('error', function (error) {
});
feedparser.on('readable', function () {
var stream = this,
meta = this.meta,
item;
while (item = stream.read()) {
var newData = item;
Buzzfeed.create({'title': newData.title, 'url': newData.link, 'source': 'nytimesTech', 'category': 'tech'}, function (err, newTitles) {
});
}
});
}
};
Now you can call the Service from any controller and provide the required URL using:
BuzzyAPI.buzzy(url);
Hope this helps.

Resources