Reuse Nodejs Api - node.js

I have a written an api in nodejs to find list of leads or customers. Now i have to use this api from another controller. How to pass query paramters from another controller and get list of leads from it. Hence will be able to reuse code.
exports.listofLeads = function (req, res) {
var param = req.query.from; var s = "initialSource"; var queryLeads = Customers.find({"attributes": { $size: 0 }} ,{"email":1}); if(! param) {
queryLeads.exec(function (err, articles) {
if (err) {
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(articles);
}
}); } else {
queryLeads.and([ { [s]: param } ]).exec(function (err, articles) {
if (err) {
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(articles);
}
});
}
};

Using require() you can access file in which you have written this function. So in other api just call this function and pass parameters as you did in first api

Related

Refactoring RESTful API into smaller functions

Background
I have a NodeJS app that is meant to be used as a RESTful API. It is connected with a MongoDB database in the backend using Mongoose. The app is built upon the idea of nested documents. It stores wikis, sections and notes with the following schema:
const noteSchema = new mongoose.Schema({ title: String, content: String });
const sectionSchema = new mongoose.Schema({ title: String, notes: [noteSchema] });
const wikiSchema = new mongoose.Schema({ title: String, sections: [sectionSchema] });
All of which are accessed via a single model of the wiki:
const wikiModel = mongoose.model("Wiki", wikiSchema);
A user can do GET, POST, PUT, DELETE requests on each of the endpoints to manipulate the data inside. If someone wants to ping the Notes endpoint (the furthest down in the hierarchy), it must first check the wiki and then the section endpoint, to ensure that each of them exists.
Here's an example:
app.get('/:wikiTitle/:sectionTitle/:noteTitle', function(req, res) {
wikiModel.findOne({ title: req.params.wikiTitle }, function(err, wiki) {
if (err) {
res.send('\nAn unkown error has occured');
console.error(err);
} else if (wiki) {
const sectionTitle = req.params.sectionTitle;
wikiModel.findOne({ 'sections.title': sectionTitle }, function(err, section) {
if (err) {
res.send('\nAn unkown error has occured');
console.error(err);
} else if (section) {
const noteTitle = req.params.noteTitle;
wikiModel.findOne({ 'sections.notes.title': noteTitle }, function(err, n) {
if (err) {
res.send('\nAn unkown error has occured');
console.error(err);
} else if (n) {
const section = n.sections.find((s) => { return s.title === sectionTitle; });
const note = section.notes.find((n) => { return n.title === noteTitle; });
if (note.content) {
res.send('\n' + note.title + '\n\n' + note.content);
} else {
res.send('\n' + note.title + '\n\n[ No content to show ]');
}
} else {
res.send('\nNo such note exists');
}
});
} else {
res.send('\nNo such section exists');
}
});
} else {
res.send('\nNo such wiki exists');
}
});
});
This is a very lengthy method and the first two queries are actually frequently throughout the app. I also understand a MongoDB query is an asynchronous operation and thus, why I put each consequent MongoDB query within it's parent (the one I wish to finish before that one begins).
Question
Is there a way to split each MongoDB query into its own method or introduce promises in a way that would shorten the code? I would rather prefer advice that ultimately causes the splitting of my code into individual methods as what you see above is one of many endpoints which all use the same queries.
So in the end result I would like to have something close to the likes of:
app.get('/:wikiTitle/:sectionTitle/:noteTitle', function(req, res) {
if (getWiki(req.params.wikiTitle)) {
// Continue with second query
if (getSection(req.params.sectionTitle)) {
// Continue with third query...
}
}
});
function getWiki(wikiTitle) {
wikiModel.findOne({ title: wikiTitle }, function(err, wiki) {
if (err) {
console.error(err);
res.send('An unknown error occured.');
} else if (wiki) {
// Send OK result to continue to next query
return wiki
} else {
res.send('No wiki found');
return null;
}
});
}
function getSection(sectionTitle) {
wikiModel.findOne({ 'sections.title': sectionTitle }, function(err, section) {
if (err) {
console.error(err);
res.send('An unknown error occured.');
} else if (section) {
// Send OK result to continue to next query
return section
} else {
res.send('No section found');
return null;
}
});
}
I am hoping this will significantly cut the length of code and also utilise re-usability of code. Any advice on how I could come close to achieving something like this is welcome.
You can definitely use callbacks in the same way as the ones call your model. For example:
app.get('/:wikiTitle/:sectionTitle/:noteTitle', function(req, res) {
getWiki(req.params.wikiTitle, function (err, title) {
if (err) {
return res.send(err);
}
getSection(req.params.sectionTitle, function (err, section) {
if (err) {
return res.send(err);
}
// Todo: use title and section, etc...
});
});
});
function getWiki(wikiTitle, cb) {
wikiModel.findOne({ title: wikiTitle }, function(err, wiki) {
if (err) {
console.error(err);
return cb('An unknown error occured.');
} else if (wiki) {
// Send OK result to continue to next query
return cb(null, wiki);
} else {
return cb('No wiki found');
}
});
}
function getSection(sectionTitle, cb) {
wikiModel.findOne({ 'sections.title': sectionTitle }, function(err, section) {
if (err) {
console.error(err);
return cb('An unknown error occured.');
} else if (section) {
// Send OK result to continue to next query
return cb(null, section);
} else {
return cb('No section found');
}
});
}
This is a standard way of using async functions in node. By convention, the first parameter is always an error parameter.
If you want your code to be cleaner, you can try to use guard clauses / early outs to exit error cases early. This will cut down on your need for if / else conditional statements.
You can also look into libraries like async for cleaner chaining of asynchronous calls.
When you are comfortable, you can also look into using promises and the 'async' javascript keyword (different from the async library above, confusing, I know) which will also allow you to cut down on the lines of code you have to write to get nice async code.
You should use async functions (Promises) like
app.get('somePath', async (req, res, next) => {
try {
const doc = await model.find({ someField: 'some value' }).exec(); // exec returns promise
res.send({ document: doc });
} catch (error) {
// here you can handle all errors or/and call next for the error middleware
next(error);
}
});

MongoDB is not updating the data

I have two modules. listingproperties and users' dashboard.
function propertyVerification(id){
listingproperty.propertyVerificationFlag = 1;
$http.put('/api/listingproperties/' + id, vm.ListingpropertiesService).success(function() {
listingproperty.propertyVerificationFlag = 1;
Notification.success('Property flagged successfully');
}).error(function() {
Notification.error('Property flagged successfully');
});
}
The above code is users' dashboard controller code. I'm trying to verify listed property by flag value to 1.
This code snippet runs perfectly but it is not reflecting on MongoDB database.
What is the wrong in above code?
Below is my server side code.
function ListingpropertiesService($resource) {
return $resource('/api/listingproperties/:listingpropertyId', {
listingpropertyId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}
Also,
exports.update = function (req, res) {
var listingproperty = req.listingproperty;
listingproperty = _.extend(listingproperty, req.body);
listingproperty.save(function (err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(listingproperty);
}
});
};
Is this correct?

I have created an API in node js in request I am getting object but while retrieving it server side showing error

I am not getting the error that why that array is not pushing into parameter
Here is my code in session.poll_questions_list.push I am trying to push array but getting an error like "Cast to ObjectID failed for value"
router.put('/session/updatepoll/:sessionID', function(req, res) {
Session.findById(req.params.sessionID, function(err, session) {
if (err) {
return res.send(err);
}
if (session) {
if (req.body.poll_enabled) {
session.poll_enabled = req.body.poll_enabled;
session.poll_type = req.body.poll_type;
session.poll_questions_list.push(req.body.poll_questions_list);
session.save(function(err, session) {
if (err) {
return res.send(err);
} else {
res.json(session);
}
})
}
if (!req.body.poll_enabled) {
session.poll_enabled = req.body.poll_enabled;
session.poll_type = "";
session.poll_questions_list = [];
session.save(function(err, session) {
if (err) {
return res.send(err);
} else {
res.json(session);
}
})
}
}
})
})

Get the return value from mongoose call back function Node.js

I have written a function like this
function create(data, res){
var history= new historyData({
owner: data
});
historyData.save(function(err, historyData) {
//To identify the error
if (err) {
console.log(err);
}
//If no error pass the team details to databsae
else {
return historyData.id;
}
});
}
and I'm trying to get the return value like this
var history = create("saddsa", res);
but it gives undefined error
I want to get the id of the created collection and pass it to another function?
Try to return a callback and get that value
function create(data, res, callback) {
var history = new historyData({
owner: data
});
historyData.save(function(err, historyData) {
//To identify the error
if (err) {
console.log(err);
callback(err)
}
//If no error pass the team details to databsae
else {
return callback(null,historyData.id);
}
});
}
// call your function like this
create("saddsa", res,function(err,result){
if(!err){
console.log(result)
}
});
replace
return historyData.id;
with
if(res) res(historyData.id);
and call
create("saddsa", function (id) { var history = id; });

Trouble to synchronise promises in Node.js using Q

I am currently doing an API in Node.JS with the framework Sails.js. I am using promises for the first time and I have some troubles to sync my promises like I want.
My main function is the following :
createCard: function(req, res) {
checkIfUserHasStripeAccount(req.user)
.then(addCreditCardToStripeAccount())
.then(function cardCreated() {
res.send(200, {
msg: 'Card created'
});
})
.catch(function handleError(err) {
res.send(err.httpCode, err.msg);
})
},
Obviously I can't add a credit card to a stripe account if the user doesn't have one.
The function checkIfUserHasStripeAccount() checks if the account exists and if not, create it.
Here is the code for this part :
function checkIfUserHasStripeAccount(user) {
var deferred = q.defer();
if (!user.idStripe) {
createStripeAccountToUser(user)
.then(function(savedUser) {
deferred.resolve(savedUser);
})
.catch(function(err) {
deferred.reject(err);
})
} else {
deferred.resolve(user);
}
return deferred.promise;
}
function createStripeAccountToUser(user) {
var deferred = q.defer();
var jsonUserToCreate = {
description: user.firstname + ' ' + user.surname,
email: user.email
};
stripe.customers.create(jsonUserToCreate, function(err, customer) {
if (err) {
deferred.reject({
httpCode: 500,
msg: 'some error'
});
} else {
user.idStripe = customer.id;
user.save(function(err, savedUser) {
if (err) {
deferred.reject({
httpCode: 500,
msg: 'some error'
});
}
deferred.resolve(savedUser);
});
}
});
return deferred.promise;
}
The problem is that the .then(addCreditCardToStripeAccount()) is executed before checkIfUserHasStripeAccount() is finished.
I can't figure out why. I thought the .then(addCreditCardToStripeAccount()) would only be executed if it received a reject or resolve.
You are correct in your line of thought.
The problem is that you are invoking your function instead of referencing it:
.then(addCreditCardToStripeAccount())
should be:
.then(addCreditCardToStripeAccount)
I expect this to work:
createCard: function (req, res) {
checkIfUserHasStripeAccount(req.user)
.then(addCreditCardToStripeAccount)
.then(function cardCreated(){
res.send(200, {msg: 'Card created'});
})
.catch(function handleError(err) {
res.send(err.httpCode, err.msg);
})
},
For future, note that the () after the function name invokes the function, as order of execution in JS will evaluate it first due to being inside the then's ().
In promise chains, always invoke only the first function. Example:
function first () { /*...*/ } // All return promise.
function second() { /*...*/ }
function third () { /*...*/ }
first() // Invoked
.then(second) // Not invoked. second() will have been bad here.
.then(third);

Resources