I'm trying to build a simple to-do list. I keep getting a cannot POST error trying to add a to-do using a form to submit. I'm not sure if I'm linking my files correctly or not while trying to follow MVC. Am I missing a module?
app.js (trimmed down because SO says I have mostly code)
const express = require("express");
const mongoose = require("mongoose");
const dotenv = require("dotenv");
const exphbs = require("express-handlebars");
const MongoStore = require("connect-mongo");
const connectDB = require("./config/db");
// config.env is where all the global variables are stored.
dotenv.config({ path: "./config/config.env" });
// This call connects to mongodb.
connectDB();
// Initialize app
const app = express();
// Body parser
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
// Handlebars
app.engine(".hbs", exphbs({ extname: ".hbs" }));
app.set("view engine", "hbs");
// Sessions
app.use(
session({
secret: "keyboard cat",
resave: false,
saveUninitialized: false,
store: MongoStore.create({ mongoUrl: process.env.MONGO_URI }),
})
);
// Passport middleware
app.use(passport.initialize());
app.use(passport.session());
// Static folder
app.use(express.static(path.join(__dirname, "public")));
const PORT = process.env.PORT || 3000;
// Routes
app.use("/", require("./routes/index"));
app.use("/auth", require("./routes/auth"));
// app.use("/todo", require("./routes/todo"));
app.listen(
PORT,
console.log(`Server running in ${process.env.NODE_ENV} mode on PORT ${PORT}`)
);
todo.js in Route
const express = require("express");
const router = express.Router();
const todosController = require("../controllers/todos");
// const { ensureAuth, EnsureGuest } = require("../middleware/auth");
router.get("/", todosController.getTodos);
router.post("/addTodo", todosController.addTodo);
todo.js in Controller
const Todo = require("../models/todos");
module.exports = {
addTodo: async (req, res) => {
try {
await Todo.create({
todo: req.body.todoItem,
done: false,
googleId: req.user.googleId,
});
console.log("To do has been added!");
res.redirect("/");
} catch (err) {
console.error(err);
}
},
};
handlebars form
<form class="center" action="/addTodo" method="POST">
<input type="text" placeholder="Add a To Do" name="todo" />
<button type="submit" class="submitButton">
<i class="fa fa-plus-square"></i>
</button>
</form>
and lastly my folder structure
Related
I'm making a authentication system, here is my index.html file i'm using nodejs, express and for database mongodb.
Before it working fine but somehow now its give me no result on visual studio i find no error but the issue is it not giving me the result the keeps loading on the localhost page, i try to change the port but same issue.
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
const port = 7000;
// for database
const db = require('./config/mongoose');
const user=require('./models/user');
// for passport authentication
const passport=require('passport');
const passportLocalStrategy=require('./config/passport-local');
const session = require('express-session');
const MongoStore = require('connect-mongo');
app.use(express.urlencoded());
app.use(cookieParser());
// for layouts
const layouts=require('express-ejs-layouts');
app.use(layouts);
// extract style and scripts from sub pages into the layout
app.set('layout extractStyles', true);
app.set('layout extractScripts', true);
//for static files
app.use(express.static('./assets'));
const path=require('path');
// set up the view engine
app.set('view engine', 'ejs');
app.set('views',path.join(__dirname,'views'));
//app.set('views', './views');
app.use(session({
name:'Authentication',
secret:'Dheeraj',
saveUninitialized:false,
resave:false,
cookie:{
maxAge:(1000*60*60)
},
store:( MongoStore.create({
mongoUrl: 'mongodb://localhost/NODEJS_AUTHENTICATION',
autoRemove : 'disabled'
},
function(err){
console.log(err || "connect-mongodb")
}))
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(passport.setUserToLocals);
const passportOauth2Strategy = require('./config/passport-google-oauth2');
const flash=require('connect-flash');
app.use(flash());
app.use(function(req,res,next){
res.locals.flash ={
'success': req.flash('success'),
'error': req.flash('error')
}
next();
});
//use express router
app.use('/',require('./routes'));
app.listen(port, function(err){
if (err){
console.log(`Error in running the server: ${err}`);
}
console.log(`Server is running on port: ${port}`);
});
I'm using node and express and I'm trying to upload some files and some information with a form. The issue is that when I try to acces to anything in the form from backend it is undefined or empty. When I use req.body it's empty and when I try to use req.files they are undefined so I don't know what to do. This is the code:
routerProgress.post("/home/upload-progress", (req, res) => {
const user_id = req.user.id;
console.log(req.body);
const weight = req.body.weight;
const front = req.files.front;
const from_side = req.files.from_side;
const backwards = req.files.backwards;
let front_id = `${v4()}-${front.file.name}`;
let from_side_id = `${v4()}-${from_side.file.name}`;
let backwards_id = `${v4()}-${backwards.file.name}`;
const date = dateFormat(result.request_date, "yyyy-mm-dd");
from.mv('../../uploads/images', front_id, (req, res) => {
if (err) console.log(err);
else console.log("File Uploaded");
})
from_side.mv('../../uploads/images', from_side_id, (req, res) => {
if (err) console.log(err);
else console.log("File Uploaded");
})
backwards.mv('../../uploads/images', backwards_id, (req, res) => {
if (err) console.log(err);
else console.log("File Uploaded");
})
const newProgress = new Progress ({
user_id,
weight,
front_id,
from_side_id,
backwards_id,
date
})
res.redirect("/home");
});
The console.log is only {} and req.files.name_defined_in_form are undefined.
Here is my app.js
import express from 'express';
const app = express();
import path from 'path';
import sequelize from './db/db.js';
import { fileURLToPath } from 'url';
import flash from 'connect-flash';
import session from 'express-session';
import passport from 'passport';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// SERVER CONFIGURATION
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Listening at ${PORT}`);
sequelize.sync({ force: false })
.then(() => console.log('Database Connected!'))
.catch(err => console.log(err));
});
// VIEW SETTINGS
app.use(express.static(__dirname + "/public"));
app.set("view engine", "pug");
// app.engine('html', require('ejs').renderFile);
app.set('views', path.join(__dirname, "/public/views"));
// BODYPARSER
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
// EXPRESS SESSION
app.use(session({
secret: 'GymApp',
resave: true,
saveUninitialized: true
}));
// CONNECT FLASH
app.use(flash());
// PASSPORT MIDDLEWARE
import passportConfig from './config/passport.js';
passportConfig(passport);
app.use(passport.initialize());
app.use(passport.session());
// GLOBAL VAR
app.use((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();
});
// ROUTES
import { routerIndex } from './routes/index.js';
import { routerProgress } from './routes/app/progress.js';
import { routerAuthentication } from './routes/authentication.js';
import { routerHome } from './routes/app/home.js'
app.use(routerIndex);
app.use(routerProgress);
app.use(routerAuthentication);
app.use(routerHome);
And here is the form done with pug:
form(class="form add-form space-down" method="POST" enctype="multipart/form-data")
div.title
h1 UPLOAD NEW PROGRESS
div.form-group
label(for="weight") Weight:
input(type="number" name="weight" class="form-control" placeholder="Enter your weight")
div.form-group
label(for="front") Upload a front photo
input(type="file" name="front")
div.form-group
label(for="from_side") Upload a from side photo
input(type="file" name="from_side")
div.form-group
label(for="backwards") Upload a backwards photo
input(type="file" name="backwards")
div.button-container
button(type="submit" class="btn btn-primary btn-color space") Upload
If anyone know what I should do to solve this issue I would be very grateful with him.
In order to access the req.files object, you need to add a specific middleware named express-fileupload that allows this functionality.
Simply run npm i express-fileupload, and then add it to your app.js, like so:
const fileUpload = require('express-fileupload');
app.use(fileUpload());
In your specific app.js, you could add it near your other middleware, such as:
import express from 'express';
const app = express();
import path from 'path';
import sequelize from './db/db.js';
import { fileURLToPath } from 'url';
import flash from 'connect-flash';
import session from 'express-session';
import passport from 'passport';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// SERVER CONFIGURATION
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Listening at ${PORT}`);
sequelize.sync({ force: false })
.then(() => console.log('Database Connected!'))
.catch(err => console.log(err));
});
// FILE UPLOAD
const fileUpload = require('express-fileupload');
app.use(fileUpload());
// VIEW SETTINGS
app.use(express.static(__dirname + "/public"));
app.set("view engine", "pug");
// app.engine('html', require('ejs').renderFile);
app.set('views', path.join(__dirname, "/public/views"));
// BODYPARSER
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
// EXPRESS SESSION
app.use(session({
secret: 'GymApp',
resave: true,
saveUninitialized: true
}));
// CONNECT FLASH
app.use(flash());
// PASSPORT MIDDLEWARE
import passportConfig from './config/passport.js';
passportConfig(passport);
app.use(passport.initialize());
app.use(passport.session());
// GLOBAL VAR
app.use((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();
});
// ROUTES
import { routerIndex } from './routes/index.js';
import { routerProgress } from './routes/app/progress.js';
import { routerAuthentication } from './routes/authentication.js';
import { routerHome } from './routes/app/home.js'
app.use(routerIndex);
app.use(routerProgress);
app.use(routerAuthentication);
app.use(routerHome);
After installing and implementing the middleware via app.use(), the req.files object should now be accessible, given you are passing the files from your form properly.
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've tried using the expressjs csurf example from https://github.com/expressjs/csurf When using the first example in the Readme, (using Ejs template language), the token validation works fine. When I try using the 'Ignoring Routes' example, on the 'GET /form' to 'POST /process' execution(just as I did in the first example), I get 'invalid token' on the 'POST /process'. The token is being passed to the form on the GET. Any ideas?
Is 'app.use(csrfProtection)' not working? (used in the non working example, if I remove the 'use(csrfP..' and use the methodology from the working example to use the csrf module, IE, passing 'csrfProtection' to the 'get' and 'post' methods, the second example works)
Works:
var cookieParser = require('cookie-parser')
var csrf = require('csurf')
var bodyParser = require('body-parser')
var express = require('express')
// setup route middlewares
var csrfProtection = csrf({ cookie: true })
var parseForm = bodyParser.urlencoded({ extended: false })
// create express app
var app = express()
app.set('view engine', 'ejs')
// parse cookies
// we need this because "cookie" is true in csrfProtection
app.use(cookieParser())
app.get('/form', csrfProtection, function(req, res) {
// pass the csrfToken to the view
var tkn = req.csrfToken()
console.log(tkn)
res.render('index', { csrfToken: tkn })
})
app.post('/process', parseForm, csrfProtection, function(req, res) {
res.send('data is being processed')
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
html/ejs:
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<form action="/process" method="POST">
<input type="hidden" name="_csrf" value="<%= csrfToken %>">
Favorite color: <input type="text" name="favoriteColor">
<button type="submit">Submit</button>
</form>
</body>
</html>
Does not work:
var cookieParser = require('cookie-parser')
var csrf = require('csurf')
var bodyParser = require('body-parser')
var express = require('express')
// setup route middlewares
var csrfProtection = csrf({ cookie: true })
var parseForm = bodyParser.urlencoded({ extended: false })
// create express app
var app = express()
app.set('view engine', 'ejs')
// parse cookies
// we need this because "cookie" is true in csrfProtection
app.use(cookieParser())
// create api router
var api = createApiRouter()
// mount api before csrf is appended to the app stack
app.use('/api', api)
// now add csrf, after the "/api" was mounted
app.use(csrfProtection)
app.get('/form', function(req, res) {
// pass the csrfToken to the view
var tkn = req.csrfToken()
console.log(tkn)
res.render('index', { csrfToken: tkn })
})
app.post('/process', parseForm, function(req, res) {
res.send('csrf was required to get here')
})
function createApiRouter() {
var router = new express.Router()
router.post('/getProfile', function(req, res) {
res.send('no csrf to get here')
})
return router
}
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app2 listening at http://%s:%s", host, port)
})
In your second example, you are not passing the csrfProtection middleware to the POST processing chain. It should be
app.post('/process', parseForm, csrfProtection, function(req, res) {
res.send('csrf was required to get here')
})