I have a route file for the admin and home pages separately. I also have difference layout files for home and admin. When I access the home and admin routes on my local dev everything is ok, but when I try to access the admin route useing site.com/admin I get Cannot GET /admin/ response. following is my server.js:
const express = require('express');
const exphbs = require('express-handlebars');
const methodOverride = require('method-override');
const flash = require('connect-flash');
const session = require('express-session');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const path = require('path');
const app = express();
// Use path
app.use(express.static(path.join(__dirname, 'public')));
// Map Global Promise
mongoose.Promise = global.Promise;
// Connect to mongoose
mongoose.connect('mongodb://localhost/skillbuild')
.then(() => console.log('MongoDB Connected...'))
.catch(err => console.log(err));
// Load Idea model
// require('./models/Idea');
// const Idea = mongoose.model('ideas');
// Express Handlebars middleware
app.engine('handlebars', exphbs({
defaultLayout: 'main'
}));
app.set('view engine', 'handlebars');
// BodyParser middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// Method Override middleware
app.use(methodOverride('_method'));
// Load routes
const home = require('./routes/home');
const admin = require('./routes/admin');
// Use routes
app.use('/', home);
app.use('/admin', admin);
// Express session middleware
app.use(session({
secret: 'keyboard cat',
resave: true,
saveUninitialized: true
}));
app.use(flash());
// Global variables
app.use(function (req, res, next) {
res.locals.success_msg = req.flash('success_msg');
res.locals.error_msg = req.flash('error_msg');
res.locals.error = req.flash('error');
next();
});
const port = 80;
app.listen(port, () => {
console.log(`Server started on port ${port}`);
});
my home routes which are in home.js routes file:
const express = require('express');
const router = express.Router();
router.all('/*', (req, res, next) => {
req.app.locals.layout = 'main';
next();
});
// index route
router.get('/', (req, res) => {
res.render('index');
});
// About route
router.get('/about', (req, res) => {
res.render('about');
});
//login route temp
router.get('/login', (req, res) => {
res.render('users/login');
});
module.exports = router;
my admin.js routes file:
const express = require('express');
const router = express.Router();
router.all('/*', (req, res, next) => {
req.app.locals.layout = 'admin';
next();
});
// admin index route
router.get('/', (req, res) => {
res.render('admin/index');
});
module.exports = router;
OK...so the problem simply was that I needed to restart the server with pm2 restart id of the node app in order to load the updated code. Problem solved.
Related
I'm currently working on a register and login system with Express, Node, Mongoose and Passport.js and the register mostly works fine , but there's a big issue with the login system. For some reason in the method I've created passport cannot read "passport" of undefined, so something is coming up as undefined but I can't seem to figure it out.
I don't know why it's not working, any help please!!
this my code
app.js
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const cors = require('cors');
const passport = require('passport');
const mongoose = require('mongoose');
const config = require('./config/database');
mongoose.connect(config.database);
mongoose.connection.on('connected', () => {
console.log('Connected to database ' + config.database);
});
mongoose.connection.on('error', (err) => {
console.log('Database error:' + err);
});
const app = express();
const users = require('./routes/users');
const port = 3000;
app.use(cors());
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.use(passport.initialize());
app.use(passport.session());
app.use('/users', users);
app.get('/', (req, res) => {
res.send('Invalid Endpoint');
});
app.listen(port, () =>{
console.log('Server started on port' + port);
});
users.js
const express = require('express');
const router = express.Router();
const passport = require('passport');
const jwt = require('jsonwebtoken');
const User = require('../models/user');
router.post('/register', (req, res, next) =>{
let newUser = new User({
name: req.body.name,
email: req.body.email,
username: req.body.username,
password: req.body.password
});
User.addUser(newUser, (err, user) => {
if(err){
res.json({success: false, msg:'Failed to register user'});
}else {
res.json({success: true , msg:'User registered'});
}
});
});
router.post('/authenticate', (req, res, next) =>{
res.send('AUTHENTICATE');
});
router.get('/profile', (req, res, next) =>{
res.send('PROFILE');
});
module.exports = router;
Your issue is with passport session. You need to use express session (remember to install in your dependencies) before it for it to work properly.
Your app.js should look like this:
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
const cors = require('cors');
const passport = require('passport');
const mongoose = require('mongoose');
const config = require('./config/database');
const session = require("express-session");
mongoose.connect(config.database);
mongoose.connection.on('connected', () => {
console.log('Connected to database ' + config.database);
});
mongoose.connection.on('error', (err) => {
console.log('Database error:' + err);
});
const app = express();
const users = require('./routes/users');
const port = 3000;
app.use(cors());
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.use(session({secret: "secret"});
app.use(passport.initialize());
app.use(passport.session());
app.use('/users', users);
app.get('/', (req, res) => {
res.send('Invalid Endpoint');
});
app.listen(port, () =>{
console.log('Server started on port' + port);
});
Also, keep in mind that body parser is deprecated for Express 4.16.0 or higher. It has been re-added in methods express.json() and express.urlencoded() so if your Express version falls into that category, you can change your app.js to:
const express = require('express');
const path = require('path');
const cors = require('cors');
const passport = require('passport');
const mongoose = require('mongoose');
const config = require('./config/database');
const session = require("express-session");
mongoose.connect(config.database);
mongoose.connection.on('connected', () => {
console.log('Connected to database ' + config.database);
});
mongoose.connection.on('error', (err) => {
console.log('Database error:' + err);
});
const app = express();
const users = require('./routes/users');
const port = 3000;
app.use(cors());
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(session({secret: "secret"});
app.use(passport.initialize());
app.use(passport.session());
app.use('/users', users);
app.get('/', (req, res) => {
res.send('Invalid Endpoint');
});
app.listen(port, () =>{
console.log('Server started on port' + port);
});
I suggest adding comments to your code to keep it neat as well.
In case anyone else runs into this error:
express-session deprecated undefined resave option; provide resave option
express-session deprecated undefined saveUninitialized option; provide saveUninitialized option app.
In addition to #raijin30 answer, I had to add the properties below (:
resave: true,
saveUninitialized: true
Explanation as to why, can be found at: Node JS session error: express-session deprecated.
Had the same problem and noticed that passport got updated on Septmeber 23rd. So, I decided to install the previous version via npm using
npm install --save passport#0.4.1
This solved the issue for me. Not really sure how or why it happened in the first place, but it might help you.
I am following the brad Traversy Nodejs Tutorial my server is connected and started also my Mongodb connection is running but localhost keep loading and not responding.
I have checked my URL for mongo connection also the password and username all are correct. I have also allow network access from all sources.
This was perfectly working before but now this keeps loading and loading
my db.js
const mongoose = require("mongoose")
const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.MONGO_URI, {
useNewUrlParser: true,
useFindAndModify: false,
useUnifiedTopology: true
})
console.log(`MongoDB connected ${conn.connection.host}`)
} catch (err) {
console.error(err)
process.exit(1)
}
}
module.exports = connectDB
my app.js
const express = require("express")
const path = require("path")
const dotenv = require('dotenv')
const morgan = require('morgan')
const exphbs = require('express-handlebars')
const passport = require('passport')
const connectDB = require('./config/db')
const routes = require('./routes/index')
const session = require("express-session")
const MongoDBStore = require('connect-mongodb-session')(session);
const mongoose = require('mongoose')
const methodOverride = require('method-override')
//locad config
dotenv.config({ path: './config/config.env' })
connectDB()
//passport config
require('./config/passport')(passport)
const app = express()
const PORT = process.env.PORT || 5000
//body parser
app.use(express.urlencoded({ extended: false }))
app.use(express.json())
//method override
// Method override
app.use(
methodOverride(function (req, res) {
if (req.body && typeof req.body === 'object' && '_method' in req.body) {
// look in urlencoded POST bodies and delete it
let method = req.body._method
delete req.body._method
return method
}
})
)
//logging
if (process.env.NODE_ENV === 'development') {
app.use(morgan('dev'))
}
//handlebars helpers
const { formatDate, truncate, stripTags, select } = require('./helpers/hbs')
//Hnadlebars
app.engine('.hbs', exphbs({ helpers: { formatDate, truncate, stripTags, select }, defaultLayout: 'main', extname: '.hbs' }));
app.set('view engine', '.hbs');
//sessions
app.use(session({
secret: 'keyboard cat',
resave: false,
saveUnitialized: false,
store: new MongoDBStore({
mongooseConnection: mongoose.connection
})
//cookie: { secure: true }
}))
//set passport middleware
app.use(passport.initialize())
app.use(passport.session())
//set global variable
app.use(function (req, res, next) {
res.locals.user = req.user || null
})
//static folder
app.use('/', express.static(path.join(__dirname, 'public')))
//Routes
app.use('/', routes);
app.use('/auth', require('./routes/auth'));
app.use('/stories', require('./routes/stories'));
//listen
app.listen(PORT, console.log(
`server is running in ${process.env.NODE_ENV} mode on port ${PORT}`
))
my ./routes/index.js
const express = require('express')
const router = express.Router()
const { ensureAuth, ensureGuest } = require('../middleware/auth')
const Story = require('../models/story')
//#desc Login/Landing Page
//#route GET/
router.get('/', ensureGuest, (req, res, next) => {
res.render("login", {
layout: "login"
})
})
//#desc Login/Landing Page
//#route GET/
router.get('/dashboard', ensureAuth, async (req, res, next) => {
console.log(req.user)
try {
const stories = await Story.find({ user: req.user._id }).lean() //plain Js object
res.render("dashboard", {
name: req.user.firstName,
stories
})
} catch (error) {
console.log('Stories error', error)
res.render('error/500')
}
})
module.exports = router
my browser
I have found if you're using middlewares then must call next function at the end this was the reason my page wasn't loading
The error was at //set global variable middleware
Everything worked just fine until all of a sudden this error occurred: ERR_TOO_MANY_REDIRECTS. I had no luck in figuring it out on my own so please help me if you can.
I use express-handlebars and express to route my pages and I thing I saw where the problem occurres. In my bookController file when I use res.render('something') no matter from what route it always redirects me to '/' and when I use res.send('something') It redirects to where it defined.
This is my app.js file:
const express = require("express");
const mongoose = require("mongoose");
const passport = require("passport");
const path = require("path");
const bodyParser = require("body-parser");
const hbs = require("express-handlebars");
const cookieParser = require("cookie-parser");
const session = require("express-session");
const MongoStore = require("connect-mongo")(session);
const flash = require("connect-flash");
const routes = require("./routes/index");
const expressValidator = require("express-validator");
const errorHandlers = require("./handlers/errorHandlers");
const app = express();
const webpack = require("webpack");
const webpackConfig = require("./webpack.config.js");
const compiler = webpack(webpackConfig);
const webpackDevMiddleware = require("webpack-dev-middleware")(
compiler,
webpackConfig.devServer
);
app.use(webpackDevMiddleware);
app.use(require("webpack-hot-middleware")(compiler));
app.use(express.static(path.join(__dirname, "public")));
app.engine(
"hbs",
hbs({
extname: "hbs",
defaultLayout: "main",
layoutsDir: __dirname + "/views/layouts",
partialsDir: __dirname + "/views/partials"
})
);
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "hbs");
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(flash());
app.use(
session({
resave: false,
saveUninitialized: false,
secret: process.env.SECRET
})
);
app.use(cookieParser());
app.use(expressValidator());
app.use((req, res, next) => {
res.locals.flashes = req.flash();
next();
});
app.use("/", routes);
app.use(errorHandlers.flashValidationErrors);
module.exports = app;
This is my index.js file
const router = require("express").Router();
const bookController = require("../controllers/bookController");
const { catchErrors } = require("../handlers/errorHandlers");
router.get("/", bookController.home);
router.post("/contact", catchErrors(bookController.contactForm));
router.post("/productPage", catchErrors(bookController.productForm));
module.exports = router;
This is my bookController file:
const mail = require("../handlers/mail");
exports.home = async (req, res) => {
res.render("index");
};
exports.contactForm = async (req, res) => {
const email = req.body.email;
const subject = req.body.subject;
const text = req.body.text;
await mail.send({ email, subject, text });
res.redirect("/");
};
exports.productForm = async (req, res) => {
console.log(req.body);
res.redirect("/");
};
I will very appreciate any help.
Thank you.
Answer which solved the question.
If res.render() does not stop the request (Same way as res.send(html)), usually means there is error in the render function. As the behaviour of res.render() is that if it errors, it will trigger next(err).
https://expressjs.com/en/api.html#res.render
When an error occurs, the method invokes next(err) internally.
Errors are quite simple to be tracked in the function, by passing an callback into the render;
res.render('index', function(err, html) {
if (err) console.error(err);
res.send(html);
});
Once you can trace the error and fix it, problem should be solved.
I generated a project with express-generator.
In my routes directory, i have 2 files : index.js and users.js, and about.js that handles the /about route.
Accessing /about results in Error 404 : Page Not found.
When adding the handler for /about in app.js, the error was gone.
./app.js:
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var indexRouter = require('./routes/index')
var aboutRouter = require('./routes/about');
var usersRouter = require('./routes/users');
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(express.static(path.join(__dirname, 'public')));
app.use('/', indexRouter);
app.use('/about', aboutRouter);
app.use('/users', usersRouter);
// 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;
./route/index.js:
var express = require('express');
var app = express();
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.json( {
message : "Home Page (Requeste for list)",
method : req.method,
Succes : "True"
});
// res.render('index', { title: 'Express' });
})
module.exports = router;
./routes/about.js:
var express = require('express');
var router = express.Router();
router.get('/about', function(req, res) {
res.send('im the about page!');
});
router.post('/about', function(req, res) {
res.send('im the about page!');
});
module.exports = router;
Rewrite your router/about.js like this
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
res.send('im the about page!');
});
router.post('/', function(req, res) {
res.send('im the about page!');
});
module.exports = router;
Since in your app.js, you already declare the prefix /about at line 24, so you do not have to do it again in router/about.js
What is happening is that in app.js you have set the root for about rout as "/about" and inside "about.js" you have specified router.get('/about') again, what will result in, for accessing the about route having to use /about/about (you may try before fix it). For you to get the result that you are expecting you should use router.get(´/´) inside about.js and in app.js keep as it is app.use('/about', aboutRouter);. You can have a look at https://expressjs.com/en/guide/routing.html for more information. Regards.
Though my rendering path is correct when I hit http://localhost:4444/admin/posts/create it shows some error like
Error: Failed to lookup view "/admin/posts/create" in views directory "D:\node practise\CMS\views"
app.js file is like
const express = require('express');
const app = express();
const path = require('path');
const exphbs = require('express-handlebars');
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/cms', { useNewUrlParser: true })
.then(db => {
console.log('MONGO CONNECTED!');
})
.catch(error => {
console.log('MONGO NOT CONNECTED!');
})
//making app to use static file
app.use(express.static(path.join(__dirname, 'public')));
//define template engine
app.set('view engine', 'handlebars');
//set default engine
app.engine('handlebars', exphbs({defaultLayout: 'home'}));
//load routes
const home = require("./routes/home/index");
const admin = require("./routes/admin/index");
const posts = require("./routes/admin/posts");
//use routes
app.use(home);
app.use("/admin", admin);
app.use("/admin/posts", posts);
//setting up server
app.listen(4444, () => {
console.log('Listening....');
});
I have posts.js that handles this route like
const express = require("express");
const router = express.Router();
router.all('/*', (req, res, next) => {
req.app.locals.layout = 'admin';
next();
})
router.get('/', (req, res) => {
res.send('It works!');
})
router.get('/create', (req, res) => {
res.render('/admin/posts/create');
})
module.exports = router;
And I have my views folder structure as
What may be the cause of error? When I try to send response it works but when I try to render the view it shows error.
Can you try res.render('admin/posts/create');?
If the view folders is set properly like this: app.set('views', './views'), you should be able to resolve simple view name like res.render('myview') under ./views folder