creating a dynamically restful api for node.js - javascript

I'm using mongodb for pretty much everything in my node.js application, and now i want create a restful application, so, i did that:
I'm trying to do just the get method, for now:
restApi.js:
var restAPI = {
get: function(method, model, sort, limit, options) {
if (method !== 'get') {
return;
}
model.find(options).sort(sort).limit(3).exec(function (error, result) {
if (error) {
return error;
} else {
return result;
}
});
},
};
And now i can require this in my route:
var restApi = require('restApi');
and use like this:
app.get('/', function(req, res, next) {
var result = restAPI.get('get', Event, 'date', 3, {'isActive': true});
res.render('/', {
result: result
});
});
Is not working, the result is undefined. Why??
How can i transform this in a async function with callback? This is possible?
Thanks! :)

You're not returning anything from restApi.get. If you're using mongoose, you could return a Promise easily enough:
var restAPI = {
get: function(method, model, sort, limit, options) {
if (method !== 'get') {
return;
}
return model.find(options).sort(sort).limit(3).exec();
},
};
Then you can use it like this:
app.get('/', function(req, res, next) {
restAPI.get('get', Event, 'date', 3, {'isActive': true}).then( function ( result ) {
res.render('/', {
result: result
});
}).catch( error ) {
// Render error page and log error
});
});

It is because your model is async. You have to pass callbacks.
Using async way is better because it is not blocking your application while waiting for response.
Example on your case:
restApi.js:
var restAPI = {
get: function(method, model, sort, limit, options, cb) {
if (method !== 'get') {
return cb("Method must be GET");
}
model.find(options).sort(sort).limit(3).exec(function (error, result) {
if (error) {
return cb(error);
} else {
return cb(null, result);
}
});
},
};
And now i can require this in my route:
var restApi = require('restApi');
and use like this:
app.get('/', function(req, res, next) {
restAPI.get('get', Event, 'date', 3, {'isActive': true}, function(err, result){
if(err)
return res.render("Error:" + err)
res.render('/', {
result: result
});
});
});
I've added cb argument to your REST API function so it is called when model async operation is done.
Router handler passes it's callback and prints output when operation is finished.

Related

ldapjs advanced search on subtree

Iam using ldapjs library for my project with standard LDAP server and iam trying to using search(). Its working right until i want to return results.
So i believe its more my misunderstanding of how javascript works rather than library as its working fine console.log
Secondly iam not sure if iam using nested search() correctly and efficiently.
Any help would be appreciated
function getPhones() {
return new Promise((resolve, reject) => {
let phones = [];
const opts = {
filter: `(objectClass=Phone)`,
scope: 'sub',
// attributes: ['*'],
};
client.search(`cn=${callserver.cn},cn=Modules`, opts, function (err, res) {
if (err) {
console.log('Error in promise', err);
}
res.on('searchEntry', function (entry) {
let newPhone = {};
const opts2 = {
filter: `(objectClass=*)`,
scope: 'sub',
};
client.search(`${entry.object.dn}`, opts2, function (err, res) {
res.on('searchEntry', function (entry2) {
newPhone = entry2.object;
console.log(newPhone); //here its logging just fine with all attributes
});
});
console.log(newPhone);// here newPhone is empty
phones.push(
{ ...entry.object, details: newPhone }
// followMeTo: entry.object.followMeTo,
// telephoneNumber: parseInt(entry.object.telephoneNumber),
);
});
res.on('end', function () {
resolve(phones);
});
res.on('err', function () {
reject('Error');
});
});
}
}
UPDATE 1:
if i try to use as suggested:
client.search(`${entry.object.dn}`, opts, function (err, res) {
res.on('searchEntry', function (entry2) {
phones.push({ ...entry.object, detail: entry2.object });
});
});
in here i cant access phones array, or nothing is pushed into it
so i have to do it this way:
client.search(`${entry.object.dn}`, opts, function (err, res) {
res.on('searchEntry', function (entry2) {
});
phones.push({ ...entry.object, detail: entry2.object });
});
but here i lose access to entry2 :-(
Losing my mind now
I am not familiar with this API, but it looks like your code would be something like this:
function getPhones() {
return new Promise((resolve, reject) => {
let phones = [];
const opts = {
filter: `(objectClass=Phone)`,
scope: "sub"
};
client.search(`cn=${callserver.cn},cn=Modules`, opts, function (err, res) {
if (err) {
console.log("Error in promise", err);
}
res.on("searchEntry", function (entry) {
const opts = {
filter: `(objectClass=*)`,
scope: "sub"
};
client.search(`${entry.object.dn}`, opts, function (err, res) {
res.on("searchEntry", function (entry2) {
phones.push({
...entry.object,
...{
details: entry2.object
}
});
});
});
res.on("end", function () {
resolve(phones);
});
res.on("err", function () {
reject("Error");
});
});
});
});
}
The problem with below code:
client.search(`${entry.object.dn}`, opts2, function (err, res) {
res.on('searchEntry', function (entry2) {
newPhone = entry2.object;
console.log(newPhone); //here its logging just fine with all attributes
});
});
console.log(newPhone);// here newPhone is empty
Is that JS executes client.search() which is an async action, and without waiting for the response continues to execute the console.log(newPhone);.
So the fix here would be to simply push phones into results when the response comes back, within the success callback.
Side note:You can also look into async await if you want to write the code that "looks" synchronous

Node.js npm mssql function returning undefined

I am using mssql with node.js to connect to an sql server db. I am trying to reduce code by wrapping the connection code in a function with one query parameter. When I call the function from with in a router.get function, it returns undefined.
Any help would be much appreciated.
function sqlCall(query) {
var connection = new sql.Connection(config, function(err) {
if (err) {
console.log("error1");
return;
}
var request = new sql.Request(connection); // or: var request = connection.request();
request.query(query, function(err, recordset) {
if (err) {
console.log("error2");
return;
}
return (recordset);
});
});
}
router code
router.get('/', function(req, res) {
var queryString = "select * from .....";
res.json(sqlCall(queryString));
//sqlCall(queryString)
});
You are trying to treat the sqlCall as a synchronous function with a return value, while the request.query function on the opposite is an asynchronous function, expecting a callback.
Since Node.js uses non blocking IO and callback structures for flow control, using an asynchronous structure based around callbacks is the way to go. In your case this could look like this:
router.get('/', function(req, res) {
var queryString = "selec * from .....";
sqlCall(queryString, function(err, data) {
if (typeof err !== "undefined" && err !== null) {
res.status(500).send({
error: err
});
return;
}
res.json(data);
});
});
with your other component looking like this:
function sqlCall(query, cb) {
var connection = new sql.Connection(config, function(err) {
if (typeof err !== "undefined" && err !== null) {
cb( err );
return
}
var request = new sql.Request(connection); // or: var request = connection.request();
request.query(query, function(err, recordset) {
cb( err, recordset );
});
});
}

expressJS : separating route, model, making exported properties from model to route to work async?

Im new to js/nodejs/express, and on my own tried to structure my file in an MVC like pattern
The problem is the console.log (at routes.js, the most important) returns undefined, while the second one returns the real data, and is executed by node respectively as well, How would I return that data in an async manner from my model to the route?
In my server.js
require('./modules/pos/routes')(app);
require('./modules/pos/models/inventory')(app);
In my routes.js
module.exports = function(app) {
Inventory = require('./models/inventory')(app);
app.get('/poss', function(req, res) {
var result = Inventory.get();
console.log('result1 is',result); // !
res.end(JSON.stringify(result));
});
}
In my inventory.js
module.exports = function(app) {
return {
get : function() {
var res;
app.conn.query('SELECT * FROM users', function(err, rows) {
res = JSON.stringify({users : rows});
console.log("result is ",res); // !
return res;
});
}
}
}
P.S executing node server in the terminal, and browsing to localhost:8000 gives
result1 is undefined
result is {"users":[{"id":1, "username": ...blah..
Your first console.log is executed before the second. And the get method doesn't return anything because the method that returns is the one inside the get. In order to make your method async add a callback, like this:
// inventory.js
module.exports = function(app) {
return {
get : function(cb) {
app.conn.query('SELECT * FROM users', function(err, rows){
if (err) {
return cb(err);
}
res = JSON.stringify({users : rows});
console.log("result is ", res);
cb(null, res)
});
}
};
};
// routes.js
module.exports = function(app) {
var Inventory = require('./models/inventory')(app);
app.get('/poss', function(req, res) {
Inventory.get(function (err, result) {
if (err) {
// do something else in case of error
return;
}
res.end(result); // you don't need to use json stringify here cause the result is serialized
});
});
}

ExpressJS re-query database after adding record to database

I'm new to expressJS and i'm wondering what is the best way to requery the database (mongo in my case) to get all the records after one is added.
exports.get = function (db) {
return function (req, res) {
var collection = db.get('notes');
collection.find({}, {}, function (e, docs) {
res.send(docs);
});
};
};
exports.create = function (db) {
return function (req, res) {
var title = req.body.title;
var note = req.body.note;
var collection = db.get('notes');
// Insert/update the note
collection.insert(
{
"title": title,
"note": note
},
function (err, doc) {
// If it failed, return error
if (err) {
res.send("There was a problem adding the information to the database. Error: "+err);
} else {
//res.redirect('/');
//res.json(db.get('notes'));
// WHAT IS THE BEST THING TO DO HERE TO GET ALL THE RECORDS INCLUDING THE ONE I'VE JUST ADDED?
exports.get(db);
}
}
);
}
};
I would replace
exports.get(db);
for
collection.find({}, {}, function (e, docs) {
res.send(docs);
});
The reason is that you are invoking this in the callback, AFTER the record has been inserted
Your exports.get function return a function, a kind of middleware I see.
Repplace
exports.get(db);
by
exports.get(db)();

How can convert this node.async code to using q? Do I need to return a promise?

In "view" method within my controller was previously using node-async but I wanted to try out using q.
I'm currently trying to convert this
exports.view = function (req, res) {
var category = req.params.category,
id = req.params.id,
ip = req.connection.remoteAddress,
slug = req.params.slug,
submission,
userId = typeof req.session.user !== 'undefined' && req.session.user.id ? req.session.user.id : null,
views;
var getSubmission = function (submissionId, callback) {
Submission.getSubmission({
id: submissionId
}, function (err, submission) {
if (err) {
callback(err);
} else if (submission) {
callback(null, submission);
} else {
callback(err);
}
});
};
async.waterfall([
function (callback) {
getSubmission(id, callback);
},
function (submission, callback) {
res.render('submission', {
title: submission.title + ' -',
submission: submission
});
}]);
To using q... I started doing something like:
var getSubmission = function(id) {
return Submission.getSubmission({
id : submissionId
}).then(function(submission) {
return submission;
});
};
q.fcall(getSubmission).then(function(submission) {
console.log(submission);
});
But it's not quite working as I intended. Am I doing something wrong here? How can I do this?
Is Submission.getSubmission a call to a database? Then you can't "chain" promises to that. You'll have to use the deferred method:
var getSubmission = function(id) {
var deferred = Q.defer();
Submission.getSubmission({
id: id
}, function(err, data){
if (err) {
deferred.reject(err);
} else {
deferred.resolve(data);
}
});
return deferred.promise;
}
getSubmission(some_id).then(successCallback, failureCallback);
You can also use Q#denodeify to convert a function using nodejs-style callbacks (function(err, data)) into a promise based function. Thus, the above can also be achieved by the following:
getSubmissionPromise = Q.denodeify(Submission.getSubmission);
getSubmissionPromise({id: some_id}).then(successCallback, failureCallback);

Categories

Resources