Node/Express Rest API - How to throw an error from mssql - javascript

I'm quite new to both javascript and Node/Express, and it's probably a newbie question, but here goes...
I'm building a Rest API, and want to throw new Error(err.message) from this function:
function hentForfatter(id, callback) {
sql.connect(config, function(err) {
if(err) {
console.log(err);
callback(err);
}
new sql.Request().query('SELECT * from Forfatter where ForfatterID = ' + id).then(function(recordset) {
callback(recordset[0]);
})
.catch(function(err) {
console.log(err);
callback(err);
});
});
}
... so I can do this in my Express API route:
router.get('/:forfatterid/quizer/:quiz_id', function(req, res, next) {
try {
db.hentQuiz(1, function(result) {
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(result));
});
}
catch (error) {
res.status(404).send(error)
}
});
I can't get my head around how to do this... Anyone that can help? :)

In node, there is a convention that the first parameter of a callback should be the potential error.
function hentForfatter(id, callback) {
sql.connect(config, function(err) {
if(err) {
console.log(err);
return callback(err); //notice the return statement
}
new sql.Request().query('SELECT * from Forfatter where ForfatterID = ' + id).then(function(recordset) {
callback(null, recordset[0]); //notice I send null for the error
})
.catch(function(err) {
console.log(err);
callback(err);
});
});
}
(I'm not sure how you get form db.hentQuiz to hentForfatter.)
router.get('/:forfatterid/quizer/:quiz_id', function(req, res, next) {
db.hentQuiz(1, function(err, result) {
if(err) return res.status(404).send(error);
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(result));
});
});

Try using two parameters if using callbacks:
callback(err, result)
And then check for
err and result.
In addition look up how promise chains work.

Related

Why does this mongodb controller pass undefined back to route?

The app is using basic Node.js, Express, and MongoDB to return some data at different routes.
Route:
router.get('/api/v1/:collection', (req, res, next) => {
try {
const data = ApiController.getAllRecipes(req, res, next);
console.log(data);
res.send(data);
} catch(error) {
res.send(error);
}
});
The methods that query the database are contained within a simple controller:
module.exports = {
getAllRecipes: async (req, res, next) => {
try {
req.app.db.collection(req.params.collection).find({}).toArray((error, result) => {
if (result.length > 0) {
console.log(result);
return result;
} else {
let error = new Error();
error.statusCode = 404;
error.message = 'No API results found.';
next(error);
}
});
} catch (error) {
next(error);
}
}
};
Inside the controller, the console.log(result); returns the correct data that I would like to be handled within the route file. However, the console.log(data); in the Route file returns undefined, even within the try/catch block.
Am I missing something in passing the data from the controller back to the route? Thank you :)
Found a solution! Since the controller is asynchronous, it doesn't need to return data, but rather save it to res.locals and execute Express' next() method to continue with the route.
Updated Route:
router.get('/api/v:versionNumber/:collection', ApiController.getAllRecipes, (req, res, next) => {
res.send(res.locals.results);
});
Updated controller:
getAllRecipes: async (req, res, next) => {
try {
req.app.db.collection(req.params.collection).find({}).toArray((error, result) => {
if (result.length > 0) {
res.locals.results = result;
next();
} else {
let error = new Error();
error.statusCode = 404;
error.message = 'No API results found.';
next(error);
}
});
} catch (error) {
next(error);
}
}

Template literal in MongoDB query with Mongoose

I'm trying to make a query with template literals, like this:
router.post('/login', middleware.isLoggedOut, function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
else
{
console.log(req.body);
var y=0;
User.findOne({'username': req.body.username, `privileges.${y}.region`: req.body.regiuni}, function(err, usr)
{
if(err)
{
console.log(err);
}
else
{
if(usr === null)
{
console.log("no usr");
}
else
{
req.logIn(usr, function(err)
{
if(err)
{
console.log(err);
}
return res.redirect('/users/' + user.username);
})
}
}
})
}
})(req, res, next);
});
I can't really get how I should use the template literal here "privileges.${y}.region" because right now it doesn't work. I get "unexpected template string" in the node shell, but vs code also seem not to interpret it as I want because it colors the code like the template literal is this:
: req.body.regiuni}, function(err, usr)
{
if(err)
{
console.log(err);
}
else
{
if(usr === null)
{
console.log("no usr");
}
else
{
req.logIn(usr, function(err)
{
if(err)
{
console.log(err);
}
return res.redirect('/users/' + user.username);
})
}
}
})
}
})(req, res, next);
});
module.exports = router;
Why does it happen and how can I fix this?
You need to have it inside of brackets, like
[`privileges.${y}.region`]: req.body.regiuni
It's an object, think about the way you'd access it.
Would you do
obj.`privileges.${y}.region`?
Nop, you'd use brackets
obj.[`privileges.${y}.region`]

In nodejs collection.find() is not fetching values from Mongodb collection.It returning nothing

app.get('/render', function(req, res) {
MongoClient.connect(dburl, function(err, db) {
if (err) throw err;
var collection = db.collection('shopping_list');
collection.find().toArray(function(err, result) {
res.send({result :result});
});
db.close();
});
});
In nodejs collection.find() is not fetching values from Mongodb collection.It returning nothing
In nodejs collection.find() is not fetching values from Mongodb collection.It returning nothing
exports.index = function(req, res) {
var queryObj = {};
UserModel.find(queryObj)
.exec(function(err, users) {
if (!users) {
console.log("users not found");
}
if (!err) {
console.log("number of users",users.length);
} else {
console.log("err",err);
}
});
};

nodejs mongoose remove hits Error: Can't set headers after they are sent

I am using mongoose to read and update and remove some documents.
The find and update and remove are working fine. Except the last data.remove(); which is not being removed and hits an error.
I am getting this error in my code below:
events.js:160
throw er; // Unhandled 'error' event
^
Error: Can't set headers after they are sent.
and the line that it is pointing to is:
res.status(200).json({
success: true
});
at the end of the code.
router.post('/some/route', function (req, res) {
if (req.isLoggedIn()) {
return res.status(403).json({});
}
MyModel.findById(req.user._id,function (err, data) {
if(err || data.rights !== 'super'){
return res.status(403).json({});
}
if(req.body.writer){
Books.update(
{ writer : req.body.id},
{ $set : { writer : req.body.writer} },
function (err) {
if(err){
res.status(500).send(err);
}
else{
res.status(200).send('updated successfully.');
}
}
);
}else{
Books.remove({writer: req.body.id}, function(err){
if (err){ return console.log(err)}
});
}
MetaInfo.findOneAndRemove({_id: req.body.id}, function (err, data) {
console.log(err);
});
Archive.findOne({_id: req.body.id},function (err, data) {
smtpTransporter.sendMail({...}, function (error, response) {
if (error) {
console.log(error);
} else {
console.log("Mail sent");
}
smtpTransporter.close();
});
data.remove();
if (err) {
console.log(err);
return res.status(200).json({
success: false,
message: 'server error',
err: err
});
}
res.status(200).json({
success: true
});
})
});
});
Basically when you do res.send or res.json it sets headers for response. When javascript finds another res.send to execute after one, it throws error that the headers are already set.
Make sure you are returning the res.send or json every time or you are using proper if else statement for it.
To elaborate :
Example 1 :
app.get('/', (req, res) => {
if(true){
res.send('first');
}
res.send('second');
});
This will throw error in console.
Example 2 :
app.get('/', (req, res) => {
if(true){
return res.send('first');
}
res.send('second');
});
No error thrown.
Example 3 :
app.get('/', (req, res) => {
if(true){
res.send('first')
}
else{
res.send('second');
}
});
No error thrown.

Node.js doesn't show results status properly in api

I'm developing a simple rest API in Node.js, and it works middling.
This is my controller code:
...
exports.listById = function(id, callback) {
Course.findById(id, function(err, courses){
if(err){
callback({error: 'Not Found'});
}
else{
callback(courses);
}
});
}
And this is my route:
app.get('/courses/:id', function(req, res){
var id = req.params.id;
courseController.listById(id, function(resp){
res.status(200).json(resp);
});
});
This code works and show results of my collection in mongodb.
But the code below, doesn't show results with postman:
app.get('/courses/:id', function(req, res){
var id = req.params.id;
courseController.listById(id, function(err, resp){
if(err){
res.status(404).send(err);
}
else{
res.status(200).json(resp);
}
});
});
exports.listById = function(id, callback) {
Course.findById(id, function(err, courses){
if(err)
return callback(new Error('Not Found')); // You must return Error by standard
callback(null, courses); // You must set first argument (error) to null
});
}
...
// You can check that id is number
app.get('/courses/:id(\\d+)', function(req, res, next) {
var id = req.params.id;
courseController.listById(id, function(err, resp) {
if(err)
return next(err); // Pass error to error-handler (see link below)
res.status(200).json(resp);
});
Best practice for callback function is first argument as error and second as result.You should
exports.listById = function (id, callback) {
Course.findById(id, function (err, courses) {
if (err) {
callback(error);
}
else {
callback(null, courses);
}
});
}
while your route should look like this:
app.get('/courses/:id', function (req, res) {
var id = req.params.id;
courseController.listById(id, function (error, courses) {
if (error) return res.status(500) // internal server error
// if I remember correctly, sources is empty array if course not found
res.status(200).json(resp);
});
});

Categories