app.js
var debug = require('debug');
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
javvar mongoose = require('mongoose');
var session = require('express-session');
var db = require('./dbconn');
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function() {
console.log('we are connected!');
});
var index = require('./routes/index');
var users =
require('./routes/users');
var signup = require('./routes/signup');
var login = require('./routes/login');
var adreqform =
require('./routes/adreqform') var dashboard =
require('./routes/dashboard')
var app = express();
// view engine setup app.set('views', path.join(__dirname, 'views'));
app.engine('hbs', exphbs({
extname: '.hbs',
defaultLayout: 'layout'
}));
app.set('view engine', 'hbs');
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: false
}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname,
'public')));
app.use(session({
secret: 'gh jewellery',
resave: true,
saveUninitialized: false
}));
app.use(function(req, res, next) {
app.locals.currentUser = req.session.user;
next();
});
app.use('/', index);
app.use('/users', users);
app.use('/dashboard',
dashboard);
app.use('/signup', signup);
app.use('/login', login);
app.use('/adreqform', adreqform);
// catch 404 and forward to error handler app.use(function (req, res,
next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler // will print stacktrace if
(app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler // no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
app.set('port', process.env.PORT || 3000);
module.exports = app;
var server = app.listen(app.get('port'), function() {
debug('Express server listening on port ' + server.address().port);
});
Notice I assign app.locals.currentUser = req.session.user; above and req.session.user gets set when my route /login is hit and here is it's code.
login.js
var express = require('express');
var router = express.Router();
var User = require('../models/user.model.js');
var app = require('../app');
/* GET signup page. */
router.get('/', function(req, res, next) {
res.render('login');
});
router.post('/', function(req, res, next) {
User.findOne({
email: req.body.email
}, function(err, user) {
var logged = false;
if (err) {
console.log(err);
} else if (!user) {
res.render('login', {
errnoacc: 'User does not exist! Please register.'
})
} else if (user && req.body.password == user.password) {
req.session.user = user;
res.render('dashboard');
} else {
res.render('login', {
errpass: 'Password does not match. Please try again!'
});
}
});
next();
});
module.exports = router;
In the above code when POST is hit, I assign req.session.user = user; if all is good I render the dashboard view, there are a layout.hbs which has navbar where I want to use app.locals.currentUser to show currentUser object.
Using in my layouts.hbs {{currentUser.username}} doesn't work.
I am new to expressjs development so I know I am missing something.
app.locals holds settings for all application, if you app gets more than one user it will overwrite the information.
app.use(function(req, res, next) {
app.locals.currentUser = req.session.user;
next();
});
You may use res.locals:
app.use(function(req, res, next){
res.locals.user = req.user;
res.locals.authenticated = ! req.user.anonymous;
next();
});
Then you can access in handlebar like:
p #{user.userName}
Related
I'm currently learning and a newbie to Node.js. I'm trying to build a simple REST API and currently getting an error 404 when try post to a particular route in postman to test if data has successfully been sent to Mongo db. I'm sure what i'm missing. I have double checked all my routes and they seem fine. It works when i make a get request and falls through when i make a post request.
This is my app.js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var Developer = require('./models/developers');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: true}));
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.use('/', indexRouter);
app.use('/users', usersRouter);
// Connect to DB
mongoose.connect('mongodb://127.0.0.1:27017');
// API Routes
var router = express.Router();
// Routes will be prefixed with /api
app.use('/api', router);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
// Test Route
router.get('/', function (req, res) {
res.json({message: 'Welcome to my simple API!'});
});
router.route('/developers')
.post(function (req, res) {
var developer = new Developer(); // New instance of sa developer
developer.firstName = req.body.firstName;
developer.lastName = req.body.lastName;
developer.jobTitle = req.body.jobTitle;
developer.save(function (err) {
if (err) {
res.send(err);
} else {
res.json('Developer was successfully fetched');
}
});
})
.get(function (req, res) {
Developer.find(function (err, developers) {
if (err) {
res.send(err);
} else
res.json(developers);
});
});
router.route('/developer/:developer_id')
.get(function (req, res) {
Developer.findById(res.params.developer_id, function (err, developer) {
if (err) {
res.send(err);
}
res.json(developer);
});
});
router.route('/developer/firstName/:firstName')
.get(function (req, res) {
Developer.find({firstName:res.params.firstName}, function (err, developer) {
if (err) {
res.send(err);
}
res.json(developer);
});
});
My model is developer.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var DevelopersSchema = new Schema({
firstName: String,
lastName: String,
jobTitle: String
});
module.exports = mongoose.model('Developers', DevelopersSchema);
To connect the database, instead of
mongoose.connect('mongodb://127.0.0.1:27017');
Use,
mongoose.connect('mongodb://127.0.0.1:27017/yourDatabaseName');
Check the doc.
Mongoose database connection require a database name in connect() method.
Your final app.js should be like,
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var logger = require('morgan');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var Developer = require('./models/developers');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: true}));
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.use('/', indexRouter);
app.use('/users', usersRouter);
// Connect to DB
mongoose.connect('mongodb://127.0.0.1:27017/my_unique_data_base_name');
// API Routes
var router = express.Router();
// Routes will be prefixed with /api
app.use('/api', router);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
// Test Route
router.get('/', function (req, res) {
res.json({message: 'Welcome to my simple API!'});
});
router.route('/developers')
.post(function (req, res) {
var developer = new Developer(); // New instance of sa developer
developer.firstName = req.body.firstName;
developer.lastName = req.body.lastName;
developer.jobTitle = req.body.jobTitle;
developer.save(function (err) {
if (err) {
res.send(err);
} else {
res.json('Developer was successfully fetched');
}
});
})
.get(function (req, res) {
Developer.find(function (err, developers) {
if (err) {
res.send(err);
} else
res.json(developers);
});
});
router.route('/developer/:developer_id')
.get(function (req, res) {
Developer.findById(res.params.developer_id, function (err, developer) {
if (err) {
res.send(err);
}
res.json(developer);
});
});
router.route('/developer/firstName/:firstName')
.get(function (req, res) {
Developer.find({firstName:res.params.firstName}, function (err, developer) {
if (err) {
res.send(err);
}
res.json(developer);
});
});
if I'm correct, the line of app.use('/api', router); does nothing.
When coming a request for /api endpoint, a response should be sent at the end of operations. The code pass the request to router. And router does nothing.
Then if createError(404) method calls res.send() or res.end() methods
you should move the use() method to the bottom of your code page:
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
Because at every single time it works before the other routes.
IMHO, using a standard coding style make more readable the program-flow.
Good luck..
I try to send a form with data in my nodejs app but I get "undefined" I am not sure does it matter but in console first I see "undefined", then POST. I have tried some "fixes" from the Internet like adding "type:'application/*+json', inflate: false" to app.use(bodyParser.json...) but nothing worked for me...
Undefined
POST /users/register 200 32.777 ms - 2346
this is my routes/users.js file:
var express = require('express');
var router = express.Router();
router.get('/register', function(req, res, next) {
res.render('register', {
'title': 'Register'
});
});
router.post('/register', function(req, res, next) {
console.log(req.body.name);
});
module.exports = router;
heres my jade file
form(method='post', action='/users/register', role='form')
.form-group
label Name
input.form-control(type='text', name='name', placeholder='Enter Name')
input.btn.btn-default(name='submit', type='submit', value='Register')
and app.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var expressValidator = require('express-validator');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var bodyParser = require('body-parser');
var flash = require('connect-flash');
var mongo = require('mongodb');
var mongoose = require('mongoose');
var db = mongoose.connection;
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(bodyParser.json({ type: 'application/*+json' }));
app.use(session({
secret: 'secret',
saveUninitialized: true,
resave: true
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(expressValidator({
errorFormatter: function(param, msg, value) {
var namespace = param.split('.'),
root = namespace.shift(),
formParam = root;
while(namespace.length) {
formParam += '[' + namespace.shift() + ']';
}
return {
param: formParam,
msg: msg,
value: value
};
}
}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(flash());
app.use(function(req, res, next) {
res.locals.messages = require('express-messages')(req, res);
next();
});
app.use('/', routes);
app.use('/users', users);
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
Routing works fine what show setting up a title to "Register", but I have problems with sending post :/
You're configuring body-parser to only accept JSON request bodies, but your form is submitted in URL-encoded format (application/x-www-form-urlencoded).
For that, you need to add the correct parser:
app.use(bodyParser.urlencoded({ extended : true }));
More information, also on the meaning of extended : true, here.
Having an issue with Passport-local. It appears neither serializeuser nor deserializeUser get called. After reading other posts on SO, it seems a lot of people who had this issue were not including bodyParser.
Here is my app.js:
var express = require('express');
var app = express();
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var db_config = require('./config/database');
var mongoose = require ('mongoose');
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
//loads passport implementation
require('./config/passport')(app);
//loads all routes
require('./config/routes')(app);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
//initialize connection to database
mongoose.connect(db_config.development);
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// development error handler
// will print stacktrace
if (app.get('env') === 'test') {
//initialize connection to database
mongoose.connect(db_config.test);
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
if(app.get('env') === 'production'){
//initialize connection to database
mongoose.connect(db_config.production);
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
}
module.exports = app;
Here is config/passport.js:
module.exports = function(app){
var passport = require ('passport');
var LocalStrategy = require('passport-local').Strategy;
var session = require('express-session');
var User = require('../models/user.js');
// =========================================================================
// passport session setup ==================================================
// =========================================================================
// required for persistent login sessions
// passport needs ability to serialize and unserialize users out of session
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
console.log('serialize');
done(null, user._id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
console.log('deserialize');
User.findById(id, function(err, user) {
done(err, user);
});
});
//configure passport http-basic strategy
passport.use(new LocalStrategy({
usernameField: "username",
passwordField: "password"
},
function(username, password, done){
User.findOne({username: username}, function(err, user){
if(err) return done(err);
if(!user || !user.validatePassword(password)) return done(null, false);
console.log("inside LocalStrategy: " + user);
return done(null, user);
});
}));
//setup express-session
app.use(session({
secret: "secret",
saveUninitialized: true,
resave: true
}));
app.use(passport.initialize());
app.use(passport.session());
return passport;
};
Here is my routes.js:
module.exports = function(app){
var routes = require('../routes/index');
var users = require('../routes/users');
var walks = require('../routes/walks');
var isAuthenticated = function(req, res, next){
if(req.isAuthenticated())
next();
res.status(401).send('You must login first.');
};
app.use('/', routes);
app.all('*', isAuthenticated);
app.use('/users', users);
app.use('/walks', walks);
};
Here is the routes/index.js:
var router = require('express').Router();
var passport = require('passport');
var controller = require('../controllers/index');
router.get('/', controller.index);
router.post('/signup', controller.signup);
router.post('/login', passport.authorize('local'), controller.login);
module.exports = router;
And finally here is the controller/index.js:
var User = require('../models/user.js');
var handleError = require('../handlers/error');
var controller = {};
controller.index = function(req, res, next) {
res.render('index', { title: 'Express' });
};
controller.signup = function(req, res){
console.log(req.body);
var user = new User();
user.username = req.body.username;
user.password = req.body.password;
user.save(function(err, user){
if(err) {
console.log(err.code);
handleError(res, err);
}
return res.send(user);
});
};
controller.login = function(req, res){
console.log('inside /login');
console.log('req.user: ' + req.user);
console.log('req.session: ');
console.log(req.session);
console.log('req.body: ');
console.log(req.body);
res.send(req.user);
};
module.exports = controller;
In POSTMAN I am first creating a user with a POST request to /signup with:
{
"username": "bob",
"password": "password123"
}
Then I POST to /login with the same credentials, here is the output:
inside LocalStrategy: { __v: 0,
username: 'bob',
password: '$2a$10$Oa/Q9C5Elsoa0P4427P6fOXWIKerlD937FYgLFrwCWwXxGW1gbsoW',
_id: 5685d6845c7b208693b71091 }
inside /login
req.user: undefined
req.session:
Session {
cookie:
{ path: '/',
_expires: null,
originalMaxAge: null,
httpOnly: true } }
req.body:
{ username: 'bob', password: 'password123' }
POST /login 200 205.704 ms - -
As you can see, the console.log() in both serializeUser and deserializeUser do not get called. Why is this? I'm at a complete loss here, I honestly have no idea what else to try.
This:
router.post('/login', passport.authorize('local'), controller.login);
Should be this:
router.post('/login', passport.authenticate('local'), controller.login);
passport.authorize() is meant for connecting third-party authorization responses to already-authenticated users.
I wrote a script which save an object to a MongoDB database using mongoose. The object is correctly save to the database, but the server crashes right after, throwing me the following error message: catch(err) { process.nextTick(function() { throw err}); }
Here's a part of my code:
users.js
var User = require('../models/user');
router.post('/register', function(req, res, next) {
[...]
// checks for errors
var errors = req.validationErrors();
if (errors) {
res.render('register', {
errors: errors,
[...]
})
} else {
var newUser = new User({
[...]
});
// Create user
User.createUser(newUser, function(err, user) {
if (error) {
throw err;
};
console.log(user);
});
[...]
}
});
module.exports = router;
user.js
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/nodeauth');
// User Schema
var UserSchema = mongoose.Schema({
[...]
});
var User = module.exports = mongoose.model('User', UserSchema);
module.exports.createUser = function(newUser, callback) {
newUser.save(callback);
}
apps.js
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var session = require('express-session');
var passport = require('passport');
var localStrategy = require('passport-local').Strategy;
var bodyParser = require('body-parser');
var multer = require('multer');
var flash = require('connect-flash');
var mongo = require('mongodb');
var mongoose = require('mongoose');
var db = mongoose.connection;
var expressValidator = require('express-validator');
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// handle file uploads
app.use(multer({dest:'./uploads'}).single('singleInputFileName'));
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// handle express session
app.use(session({
secret: 'secret',
saveUninitialized: true,
resave: true
}));
// passport
app.use(passport.initialize());
app.use(passport.session());
// validator
app.use(expressValidator({
errorFormatter: function(param, msg, value) {
var namespace = param.split('.')
, root = namespace.shift()
, formParam = root;
while(namespace.length) {
formParam += '[' + namespace.shift() + ']';
}
return {
param : formParam,
msg : msg,
value : value
};
}
}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
// connect flash
app.use(flash());
app.use(function (req, res, next) {
res.locals.messages = require('express-messages')(req, res);
next();
});
app.use('/', routes);
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
You shouldn't throw error you should return it in handler to let clients know if there is a database error creating the user. Only throw when caller can catch error, async code cannot be caught easily. Promises enable throwing errors but not callbacks.
I am developing an application in Express Js. When I try to run the application I get this error:
My app.js file is like this:
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
var server = app.listen(3000, function() {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
module.exports = router;
My index.js is like this:
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function (req, res, next) {
res.render('index', {title: 'Polls'});
});
router.get("/list", function (req, res, next) {
Poll.find({}, 'question', function (error, polls) {
res.json(polls);
});
});
router.get("/poll", function (req, res, next) {
var pollId = req.params.id;
// Find the poll by its ID, use lean as we won't be changing it
Poll.findById(pollId, '', {lean: true}, function (err, poll) {
if (poll) {
var userVoted = false,
userChoice,
totalVotes = 0;
// Loop through poll choices to determine if user has voted
// on this poll, and if so, what they selected
for (c in poll.choices) {
var choice = poll.choices[c];
for (v in choice.votes) {
var vote = choice.votes[v];
totalVotes++;
if (vote.ip === (req.header('x-forwarded-for') || req.ip)) {
userVoted = true;
userChoice = {_id: choice._id, text: choice.text};
}
}
}
// Attach info about user's past voting on this poll
poll.userVoted = userVoted;
poll.userChoice = userChoice;
poll.totalVotes = totalVotes;
res.json(poll);
} else {
res.json({error: true});
}
});
});
router.get("/create", function (req, res, next) {
var reqBody = req.body,
// Filter out choices with empty text
choices = reqBody.choices.filter(function (v) {
return v.text != '';
}),
// Build up poll object to save
pollObj = {question: reqBody.question, choices: choices};
// Create poll model from built up poll object
var poll = new Poll(pollObj);
// Save poll to DB
poll.save(function (err, doc) {
if (err || !doc) {
throw 'Error';
} else {
res.json(doc);
}
});
});
module.exports = router;
And user.js is this:
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
module.exports = router;
I tried to find my solution on SO, but couldn't. Feel free to tell me if i need to provide any other file. Any help?
You should define routes in your index.js like you do in user.js.
app.use('/', routes) in your code expects routes to be an instance of a Router, but you're exporting an object with functions instead of that.
So your index.js file should have the following structure:
var express = require('express');
var router = express.Router();
router.get("/", function (req, res) {
res.render('index');
});
router.get("/list", function(req, res) {/*list implementation*/});
....
module.exports = router;