req.params.id is undefined, I can't figure out why - node.js

Here is the url in browser:
http://localhost:3001/user/59cc018171149931f4e435ac
This is the code for the route:
router.get("/new", middleware.userLoggedIn, function(req, res){
console.log(req.params.id);
//find user by id
User.findById(req.user._id, function(err, foundUser){
if(err) {
console.log(err);
} else {
res.render("characters/addCharacter", {user: foundUser});
}
});
});
This is the middleware:
middlewareObj.userLoggedIn = function(req, res, next) {
// eval(require('locus'));
if (req.isAuthenticated() && req.params.id.equals(req.user._id)) {
return next();
}
res.redirect("/login");
};`
When I run the app everything works fine. Expect the request on the route above, wich giving me the error "TypeError: Cannot read property 'equals' of undefined". When I take off the middleware and try to console.log(req.params.id), it returns "undefined". What am I doing wrong?
Edit:
I have my route configured in app.js:
app.use("/user/:id/characters", characterRoutes);
So the ":id" is there.
When i use /new/:id instead of /new geting new error message:
"Cannot GET /user/59c23b864262fc2c186677be/characters/new"

use /new/:id instead of /new
router.get("/new/:id", middleware.userLoggedIn, function(req, res){
console.log(req.params.id);
//find user by id
User.findById(req.user._id, function(err, foundUser){
if(err) {
console.log(err);
} else {
res.render("characters/addCharacter", {user: foundUser});
}
});
});

You have to specify the parameter you want in your path, like so /new/:id and then you can use req.params.id in your code.
Here's the Express documentation for this part

cast req.params into any first:
let params: any = req.params
and then params.id should work

Related

Getting Information from Req.User() into Req.params() in ExpressJS

After people log into my Express app, I'd like to redirect them to a url that reads:
www.mysite.com/:user
What I'm having trouble with is that my req.params object is coming up as an empty object literal when people get re-directed after logging in.
Ideally what I'd like to do is to somehow take the information stored in req.user and pass some of that information into the URL.
So basically I'd like to get from here:
router.post('/login',
passport.authenticate('local', {successRedirect:'/', failureRedirect: '/login', failureFlash: true}));
To here:
router.get('/:user', function(req, res) {
//stuff
}
After logging in the req.user object reads like this:
{
username: joesmith#mail.com,
name: Joe Smith,
password: dkei348#$kDL^583L,
formulas: []
}
And the code I'm attempting to use is as follows:
router.get('/:user', function(req, res) {
var user = req.user.name;
req.params = {
"user": user
}
But this doesn't work because initially req.user.name is undefined if someone isn't already logged in, so I can't get past the console error.
Apparently I don't understand how req.params is generated in enough detail to get around this problem.
Thank you.
If you want to have username in parameters you shoud redirect to '/' + req.user.name); because '/' doesn't have any params. That's why it is undefined. (additionaly you shoud check if parameter is defined and handle the error, so instead of console error you get error 404 or get to next, proper routing path).
Passport Documentation privides examples of doiung it:
app.post('/login',
passport.authenticate('local'),
function(req, res) {
// If this function gets called, authentication was successful.
// `req.user` contains the authenticated user.
res.redirect('/' + req.username);
});
or more complex custom callback :
app.get('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/' + user.name);
});
})(req, res, next);
});
But I think it is not a good practice and safer would be to redirect to the proper page/content by req.user value without putting it to URL, for example setting req.auth. and then using next(); instead of res.redirect('/' + user.name); to get to the next middleware. There username would be taken from req.auth.username, not from /:username.
How does the structure of your routing looks? You shoud make sure router.get('/:user' .. is not before router.get('/login'...
Looks like you are wanting to access whatever /:user value is. e.g. www.mysite.com/stretch0. Therefore you would access it like var user = req.params.user;
You can provide a custom handler, instead of letting Passport do all the redirecting:
app.post('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) {
req.flash('error', 'Unable to authenticate user');
return res.redirect('/login');
}
if (! user) {
return res.redirect('/login');
}
req.logIn(user, function(err) {
if (err) {
req.flash('error', 'Unable to log in user');
return res.redirect('/login');
}
return res.redirect('/' + user.username);
});
})(req, res, next);
});
This does mean that each logged-in user gets their "personal" URL, because you're redirecting to /USERNAME. I'm not sure from your question if that's actually your intention.

Undefinded error

route.js
router.get('/restful', function(req, res){
console.log("before");
User.show_deatils(req, res, function(err, resultArray){
if(!err) {
req.session.resultArray=resultArray;
}
});
console.log(req.session.resultArray);
res.render('restful',{resultArray:req.session.resultArray});
});
I don't know why I am getting as undefined when I am doing it console.log() in the above position.If I do console.log() just after the req.session.resultArray=resultArray then we are getting the result array.
I want to display this resultArray in my view.ejs. Can anyone suggest me how to solve it.What is the thing I am missing it out?
The console.log runs before the async function actually gets the details from the database. so you get undefined.
Do the render inside the callback. i.e, after you assign result array to session.
router.get('/restful', (req, res, next) {
User.show_deatils(req, res, function(err, resultArray) {
if(!err) {
req.session.resultArray=resultArray;
return res.render('restful' {resultArray:req.session.resultArray}));
}
});
});
Just do like this
router.get('/restful', function(req, res){
console.log("before");
User.show_deatils(req, res, function(err, resultArray){
if(!err) {
res.render('restful',{resultArray:resultArray});
}
});
});
I think this is what you want.

Multiple callbacks in express

I have 2 schemas : Blogdemo and Review. Both in the same file : landing.ejs
I want both the content of both the schemas to appear on the landing page.
Code :
app.get('/', function (req, res,next) {
Blogdemo.find({}).sort([['_id', -1]]).limit(3).exec(function(err,allBlogs) { //finds the latest blog posts (upto 3)
if(err) {
console.log(err);
} else {
res.render("landing", {blog : allBlogs , moment : now});
}
})
next();
}, function (req, res) {
Review.find({}).sort([['_id', -1]]).limit(3).exec(function(err,allReviews) { //finds the latest reviews (upto 3)
if(err) {
console.log(err);
} else {
res.render("landing", {review : allReviews, moment : now});
}
})
})
I get the error : "review is not defined". If I change the order of the callbacks, I get the error : "blog is not defined". I understand that something is wrong with the callbacks.
I browsed through the express docs and used this :
app.get('/', function (req, res, next) {
console.log('Request URL:', req.originalUrl)
next()
}, function (req, res, next) {
console.log('Request Type:', req.method)
next()
})
This works perfectly.But I'm following the exact pattern and it's not working. What am I doing wrong?
From what I can see you are doing one thing wrong: placing next() outside the async scope.
Try this:
app.get('/', function(req, res, next) {
Blogdemo.find({}).sort([
['_id', -1]
]).limit(3).exec(function(err, allBlogs) { //finds the latest blog posts (upto 3)
if (err) next(err);
res.locals.blog = allBlogs;
res.locals.moment = now;
next();
})
}, function(req, res) {
Review.find({}).sort([
['_id', -1]
]).limit(3).exec(function(err, allReviews) { //finds the latest reviews (upto 3)
if (err) return next(err);
res.locals.review = allReviews;
res.render("landing", res.locals); // 2nd argument is optional.
})
})
I think, what you are doing wrong is rendering same page 2 times with res.render and passing one of the two variables each time, that's why the other one is coming as undefined.
You should render the landing page in the last callback, and just pass variables from first callback to second.
To pass variables from one callback to another, you can use res.locals.
Also, you should put next() inside the callback of find. so that it passes the variable to next callback correctly.
Try this:
app.get('/', function (req, res,next) {
Blogdemo.find({}).sort([['_id', -1]]).limit(3).exec(function(err,allBlogs) { //finds the latest blog posts (upto 3)
if(err) {
console.log(err);
next();
} else {
//set variable in `res.locals` and pass to next callback
res.locals.blog = allBlogs;
next();
}
})
}, function (req, res) {
Review.find({}).sort([['_id', -1]]).limit(3).exec(function(err,allReviews) { //finds the latest reviews (upto 3)
if(err) {
console.log(err);
} else {
allBlogs = res.locals.blog;
res.render("landing", {blog : allBlogs ,review : allReviews, moment : now});
}
})
})
For more information on res.locals read Express res.locals documentation.
Hope this helps you!

Mongoosedb: query by username

Problem Question: I am using MongooseDB with Nodejs and I have user schema
var UserSchema = new mongoose.Schema({
userEmail: String
});
how would I query using the userEmail?
I tried following but no result. On my postman i get cast to ObjectId failed error
router.get('/:userEmail', function(req, res, next) {
User.find(req.params.userEmail, function (err, userDetails) {
if(err){
return next(err);
}res.json(userDetails);
})
});
You need to create a query object or document that has the userEmail property and a value from the req.params object. In your case, this would be:
router.get('/:userEmail', function(req, res, next) {
User.find({ "userEmail": req.params.userEmail }, function(err, userDetails) {
if(err){
return next(err);
}
res.json(userDetails);
});
});
Please try this syntax
router.get('/:userEmail', function(req, res, next) {
User.find({"userEmail":req.params.userEmail}, function (err, userDetails) {
if(err){
return next(err);
}res.json(userDetails);
})
});
You have to put condition on which field you want to query data.
I am unable to reproduce your error "ObjectId failed error". However, I am adding another answer to give you more options.
The following things are slightly different from other answers:-
1) "lean()" is used to ensure that you will be returned a plain JavaScript object
2) Excluded the "_id" from JSON response though I am not sure whether you need the "Id" in the response. This is just to check whether "id" in response is causing the problem.
router.get('/:userEmail', function(req, res, next) {
User.find({"userEmail": req.params.userEmail}, {"_id":false}).lean().exec(function(err, users) {
if (err) {
return next(err);
}
console.log(users);
res.json(users);
});
});

node js express Whil using app.param 4 url get request doesn't work

I am using app.param to enter a parameter into the url which is the user username and it works except that any get requests right after that do not load the html page for the client. I am not getting any type of error except after the page fails to load i get a 404 error on the page. What could be the issue, i even tried router.param instead and got the same result. obviously the functionallity requires this to work on multiple pages.
//Profile views for other users
app.param('username', function(req, res, next, username) {
User.findOne({ 'local.username' : username }, function(err, user) {
if(err)
throw err;
if(user==null)
return false;
req.person = user;
next();
});
});
app.get('/:username', function(req, res) {
Profile.findOne({ 'pic.username' : req.person.local.username }, function(err, profilepic) {
if(err) {
throw err;
}
console.log(profilepic);
res.render('pages/visitprofile', {
user : req.person,
profilepic : profilepic
});
});
});
app.get('/photos/:username', function(req, res) {
Profile.findOne({ 'pic.username' : req.person.local.username }, function(err, profilepic) {
if(err)
throw err;
res.render('pages/photos', {
profilepic : profilepic
});
});
});
app.listen(3000);
console.log('express is listening on port 3000');
When you are using app.get('/:username', callback) syntax, you need to look for req.params.username.
app.get('/photos/:username', function(req, res) {
res.send(req.params.username);
}

Resources