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);
});
});
Related
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);
}
});
};
var express = require('express');
var search = express.Router();
search.get('/', function(req, res, next) {
console.log('1');
dbCall(function(error, result) {
if (error) {
res.status(404).json();
} else {
res.json(result);
}
});
console.log('last');
next();
});
var dbCall = function(callback) {
var couchbase = require('couchbase');
var cluster = new couchbase.Cluster('couchbase://127.0.0.1');
var bucket = cluster.openBucket('default');
var doc;
var ViewQuery = couchbase.ViewQuery;
var query = ViewQuery.from('dev_test', 'allData');
bucket.query(query, function(err, viewResults) {
if (err) {
callback(err, null);
} else {
console.log('inqueryCall');
var results = viewResults;
callback(null, results);
console.log(results);
}
});
};
module.exports = search;
Here's the error that I get is :
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:346:11)
Can someone please explain the issue here(not just the solution)?
I've added console.log and the issue here is that the couchbase call to async
Remove next() call, that is causing this error. next() is used in middleware to pass the flow to next middleware or endpoint/route
search.get('/', function(req, res, next) {
dbCall(function(error, result) {
if (error) {
res.status(404).json();
} else {
res.json(result);
}
});
});
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.
I am using Express.js for my app and mongodb for database (also mongodb Nativ driver).
I created a model with two functions, for getting posts and comments:
// Get single Post
exports.posts = function(id,callback){
MongoClient.connect(url, function (err, db) {
if (err) {
console.log('Unable to connect to the mongoDB server. Error:', err);
} else {
console.log('Connection established to', url);
var collection = db.collection('posts');
collection.find({psotId:id}).limit(1).toArray(function (err, result) {
if (err) {
return callback(new Error("An error has occured"));
} else {
callback(null,result);
}
db.close();
});
}
});
}
// Get post comments
exports.comments = function(id,callback){
MongoClient.connect(url, function (err, db) {
if (err) {
console.log('Unable to connect to the mongoDB server. Error:', err);
} else {
console.log('Connection established to', url);
var collection = db.collection('comments');
collection.find({postId:id}).toArray(function (err, result) {
if (err) {
return callback(new Error("An error has occured"));
}
else {
callback(null,result);
}
db.close();
});
}
});
}
and I created a route to show single post:
var post = require('../models/post');
//Get single post
router.get('/post/:postId',function(req,res, next){
var id = parseInt(req.params.postId);
post.posts(id,function(err,post){
if(err){
console.log(err)
}else{
post.comments(post[0].id,function(err,comments){
if(err){
console.log(err)
}
else{
res.render('blogPost',{post:post,comments:comments})
}
})
}
})
})
When I run this code I get this error:
TypeError: Object [object Object] has no method 'comments'
When I use this two function separately its work fine:
I mean like this :
var post = require('../models/post');
//Get single post
router.get('/post/:postId',function(req,res, next){
var id = parseInt(req.params.postId);
post.posts(id,function(err,post){
if(err){
console.log(err)
}else{
res.render('blogPost',{post:post})
}
})
})
//Get post comments
router.get('/post/1',function(req,res, next){
post.comments(1,function(err,comments){
if(err){
console.log(err)
}else{
res.render('blogPost',{comments:comments})
}
})
})
But when I use post.comments as callback for post.posts I get an error.
I wants know why this happening? After some research I couldn't find a solution and I an getting confused.
In your source code you have the following:
var post = require('../models/post');
//Get single post
router.get('/post/:postId',function(req,res, next){
var id = parseInt(req.params.postId);
post.posts(id,function(err,post){
if(err){
console.log(err)
}else{
post.comments(post[0].id,function(err,comments){
if(err){
console.log(err)
}
else{
res.render('blogPost',{post:post,comments:comments})
}
})
}
})
})
when you are calling post.posts you have a callback and there you have a return value which you called post (which it is the same variable name of var post = require('../models/post');
Basically change it in the callback like this:
var post = require('../models/post');
//Get single post
router.get('/post/:postId',function(req,res, next){
var id = parseInt(req.params.postId);
post.posts(id,function(err,posts){ //HERE changed post into posts
if(err){
console.log(err)
}else{
post.comments(posts[0].id,function(err,comments){
if(err){
console.log(err)
}
else{
res.render('blogPost',{post:posts,comments:comments})
}
})
}
})
})
EDIT: for better understanding I would change var post = require('../models/post'); into var postModel = require('../models/post'); SO it is much more understandable
EDIT 2: since he posted the real version code
Basically you have the same problem, line 37 of route.js is overriding the movie variable.
You have to call the variable that comes back form the callback with another name, for example movieslike you used to do in the other 2 above.
router.get('/m/:movieId',function(req,res, next){
var id = parseInt(req.params.movieId);
movie.get(id,function(err,movies){
if(err){
console.log(err)
}else{
movie.subtitles(movies[0].imdb,function(err,subs){
if(err){
console.log(err)
}
else{
res.render('moviePage',{movie:movies,subtitles:subs})
}
})
}
})
})
If you copy-pasted this from your source then its because you mispelled the method.
post.commencts
should be
post.comments
I am using express session to login user.
Middleware:
var requireLogin = function (req, res, next) {
if (req.session.user) {
next();
} else {
res.redirect('/');
}
}
Route:
app.post('/login', requireLogin, routes.login);
exports.login = function (req, res) {
var query = {username:req.body.username, password:req.body.password};
User.find(query, function (err, data) {
if (data) {
req.session.user = data;
console.log(data);
res.redirect('/home');
} else {
console.log(err);
res.redirect('/');
}
});
};
When I enter a wrong username and password, it still redirect to home, but the data is null.
find returns an array of match results and findOne returns a matching document.
I guess findOne is appropriate for this case.
app.post('/login', requireLogin, routes.login);
exports.login = function (req, res) {
var query = {username:req.body.username, password:req.body.password};
User.findOne(query, function (err, data) {
if (data && !err) {
req.session.user = data;
console.log(data);
res.redirect('/home');
} else {
console.log(err);
res.redirect('/');
}
});
};
Because find returns an array of results, if (data) will still evaluate to true even if it's empty.
findOne would be more appropriate, because you are looking for just the one user with that unique username/password combination. This way if (data) will only evaluate to true if a matching User if found.
User.findOne(query, function (err, data) {
if (err) {
// the username/password could be valid (or not),
// but there's no way to tell because there was some server error
console.log(err);
res.redirect('/');
} else if (data) {
// a user was found that matched the query
req.session.user = data;
console.log(data);
res.redirect('/home');
} else {
// there is no User that matches the query
res.redirect('/');
}
});