Cannot POST error on form submit with nodejs backend - node.js

I am using the following stack :
React
PassportJS
NodeJS
Express and express-session
create-react-app with webpack dev server proxying API requests to my node server as mentioned in this article
When I do a form submit, I get an error Cannot POST however when I submit to the SAME url using POSTMAN or curl XPOST, I get results. Here is my server.js code :
'use strict';
const PORT = process.env.PORT || 3001;
const express = require('express');
const app = express();
const path = require('path');
const passport = require('passport')
const initPassport = require('./passport/init');
const session = require('express-session')
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser')
const configDB = require('./config/database.js');
const MongoStore = require('connect-mongo')(session);
var flash = require('connect-flash');
//Connect to mongo
mongoose.connect(configDB.url, {
useMongoClient: true
}).then(() => console.log('connection with database succeeded'))
.catch(err => console.error(err));
// Initialize Passport
initPassport(passport);
// Serve static assets
app.use(express.static(path.resolve(__dirname, '..', 'build')));
//use cookie parser to store data
app.use(cookieParser());
app.use(session({
secret: 'mysecret',
store : new MongoStore ({
db : mongoose.connection.db,
host : '127.0.0.1',
port : '27017',
url : configDB.url
}),
maxAge : 2 * 60 * 60 * 1000,
resave: false,
saveUninitialized: false
})); // session secret
app.use(bodyParser.urlencoded({ extended: false }));
app.use(passport.initialize());
app.use(passport.session()); // persistent login sessions
app.use(flash()); // use connect-flash for flash messages stored in session
app.post('/signup', passport.authenticate('signup', {
successRedirect: '/',
failureRedirect: '/signup'
}));
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}!`);
});
Form PAGE :
import React, { Component } from 'react';
import constants from 'constants/AuthPageConstants';
class RegisterForm extends Component {
render() {
return (
<div className="tab-pane fade in" id="basic-tab2">
<form action="/signup" method="POST">
<div className="text-center">
<div className="icon-object border-success text-success"><i className="icon-plus3"></i></div>
<h5 className="content-group">{constants.register_form_title} <small className="display-block">{constants.register_form_subtitle}</small></h5>
</div>
<div className="form-group has-feedback has-feedback-left">
<input type="text" name="username" className="form-control" placeholder={constants.register_username_placeholder} />
<div className="form-control-feedback">
<i className="icon-user-check text-muted"></i>
</div>
</div>
<div className="form-group has-feedback has-feedback-left">
<input type="password" name="password" className="form-control" placeholder={constants.register_password_placeholder} />
<div className="form-control-feedback">
<i className="icon-user-lock text-muted"></i>
</div>
</div>
<div className="form-group has-feedback has-feedback-left">
<input type="text" name="email" className="form-control" placeholder={constants.register_email_placeholder} />
<div className="form-control-feedback">
<i className="icon-mention text-muted"></i>
</div>
</div>
<div className="content-divider text-muted form-group"><span>Additions</span></div>
<div className="form-group">
<div className="checkbox">
<label>
<input type="checkbox" className="styled" />
{constants.tos_txt.substring(0, constants.tos_txt.indexOf(" "))} {constants.tos_txt.substr(constants.tos_txt.indexOf(" ") + 1)}
</label>
</div>
</div>
<button type="submit" className="btn bg-indigo-400 btn-block">Register <i className="icon-circle-right2 position-right"></i></button>
</form>
</div>
)
}
}
export default RegisterForm
Signup passport strategy
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/user');
var bCrypt = require('bcrypt');
module.exports = function(passport){
passport.use('signup', new LocalStrategy({
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, username, password, done) {
console.log("In Signup");
findOrCreateUser = function(){
// find a user in Mongo with provided username
User.findOne({ 'username' : username }, function(err, user) {
// In case of any error, return using the done method
if (err){
console.log('Error in SignUp: '+err);
return done(err);
}
// already exists
if (user) {
console.log('User already exists with username: '+username);
return done(null, false, req.flash('message','User Already Exists'));
} else {
// if there is no user with that email
// create the user
var newUser = new User();
// set the user's local credentials
newUser.username = username;
newUser.password = createHash(password);
newUser.email = req.param('email');
newUser.firstName = "firstName";
newUser.lastName = "lastName";
// save the user
newUser.save(function(err) {
if (err){
console.log('Error in Saving user: '+err);
throw err;
}
console.log('User Registration succesful');
return done(null, newUser);
});
}
});
};
// Delay the execution of findOrCreateUser and execute the method
// in the next tick of the event loop
process.nextTick(findOrCreateUser);
})
);
// Generates hash using bCrypt
var createHash = function(password){
return bCrypt.hashSync(password, bCrypt.genSaltSync(10));
}
}
UPDATE
The issue appears to be due to the presence of the proxy. The form submit works if I directly call the nodejs backend API which is running on a different port (by allowing CORS) and remove the proxy. If I insert the proxy, and make the form point to the weback dev server, then form submit does not call the my nodeJS API. However, proxying works with curl and POSTMAN. Weird how curl works and form submit doesn't. Any pointers here will be helpful.

try to clear browser cache . if you are using chrome
go to settings
type cache in search
browse to bottom and clear cache .
if it doesnt solve the problem please write back

Related

Can't redirect after Mongoose query

I am trying to create a website with user accounts.
But can't redirect after Mongoose save query in register page.
Here is NodeJS index.js file
const express = require('express')
const app = express();
const cors = require('cors');
const mongoose = require('mongoose');
const CryptoJS = require('crypto-js');
const jwt = require('jsonwebtoken');
const dotenv = require('dotenv');
const User = require('./models/User');
dotenv.config();
app.set('view engine', 'ejs');
app.use(cors());
app.use(express.urlencoded({extended: true}));
app.use(express.json());
app.use(express.static('public'));
app.use(express.static('partials'));
app.use(express.static('images'));
app.use(express.static('assets'));
mongoose.connect(process.env.MONGO_URL)
.then(() => {
console.log('DB is connected');
})
.catch((err) => {
console.log(err);
});
app.post('/register', async (req, res) => {
const newUser = new User({
email: req.body.email,
password: CryptoJS.AES.encrypt(req.body.password, process.env.PASS_SEC).toString()
})
try {
const savedUser = await newUser.save();
res.redirect('/')
} catch (err) {
console.log(err)
}
})
(of course app.get('/') and app.get('/login') exists in my index.js file)
My register page (register.ejs)
<%- include('./partials/header') %>
<div class='container'>
<div class="login">
<h1 class='heading'>Register</h1>
<div class='form-block'>
<form action="/register" method="POST">
<label class='label'>Email</label>
<input class='input' type='email' name='email' placeholder='example#mail.com' required/>
<label class='label'>Password</label>
<input class='input' type='password' name='password' placeholder='********' required/>
<input class='button' type='submit' value='Sign Up' />
</form>
</div>
</div>
</div>
<%- include('./partials/footer') %>
Instead of redirect to main page I get json data of saved User.
How to fix that?

MERN Stack: POSTing data to database with Express/React

I'm new to the MERN stack and backend programming. I have a React form that I want to submit to an MLab database using Express. I am unable to successfully POST the form data to the database. I'm not sure if I'm taking the correct approach or not. My form is working and I am able to log the fields, I run into problems when trying to do a POST request to submit the form data.
Here is my form:
import React from 'react';
import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Form, FormGroup, Label, Input } from 'reactstrap';
class AddBookModal extends React.Component {
constructor(props) {
super(props);
this.state = {
modal: false,
bookTitle: '',
author: '',
genre: ''
};
this.toggle = this.toggle.bind(this);
this.onSubmit = this.handleSubmit.bind(this);
}
toggle() {
this.setState(prevState => ({
modal: !prevState.modal
}));
}
handleSubmit = (event) => {
event.preventDefault();
const data = this.state;
//console.log("Data from form :" + data.bookTitle, data.author, data.genre);
}
handleInputChange = (event) => {
event.preventDefault();
this.setState({
[event.target.name]:
event.target.value
});
}
render() {
const {bookTitle} = this.state;
const {author} = this.state;
const {genre} = this.state;
return (
<div>
<Button id="add-book-button" onClick={this.toggle}>Add Book</Button>
<Modal isOpen={this.state.modal} toggle={this.toggle} className={this.props.className}>
<ModalHeader toggle={this.toggle}>Add Book</ModalHeader>
<ModalBody>
<Form method="POST" action="/profile" id="add-book-form" onSubmit={this.handleSubmit} >
<FormGroup>
<Label for="book-title-label">Book Title</Label>
<Input
value={bookTitle}
name="bookTitle"
onChange={this.handleInputChange}
placeholder="Enter name of book" />
</FormGroup>
<FormGroup>
<Label for="book-author-label">Author</Label>
<Input
value={author}
name="author"
onChange={this.handleInputChange}
placeholder="Enter author of book" />
</FormGroup>
<FormGroup>
<Label for="exampleSelect">Genre</Label>
<Input
onChange={this.handleInputChange}
value={genre}
type="select"
name="genre"
id="exampleSelect">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</Input>
</FormGroup>
<ModalFooter>
<Button color="primary" type="submit" onClick={this.toggle}>Submit</Button>{' '}
<Button color="secondary" onClick={this.toggle}>Cancel</Button>
</ModalFooter>
</Form>
</ModalBody>
</Modal>
</div>
);
}
}
export default AddBookModal;
Here is my Express route:
const router = require('express').Router();
const bodyParser = require('body-parser');
var urlencodedParser = bodyParser.urlencoded({ extended: false });
// localhost:3000/profile
// User Model
const User = require('../../models/user-model');
const Book = require('../../models/book-model');
// Checks if user is not logged in
const authCheck = (req, res, next) => {
if(!req.user) {
// If user is not logged in, redirect them to login page
res.redirect('/auth/login');
}
else {
// If user is logged in call next in router.get
next();
}
};
router.get('/', authCheck, (req, res) => {
res.send('you are logged in, this is your profile : ' + req.user);
});
router.post('/', urlencodedParser, (req, res) => {
console.log(req.body);
const newUser = new User({
name: req.body.name,
username: req.body.username,
githubID: req.body.githubID,
profileUrl: req.body.profileUrl,
avatar: req.body.avatar,
books: {
bookTitle: req.body.bookTitle,
author: req.body.author,
genre: req.body.genre
}
});
newUser.save()
.then(data => {
res.json(data)
})
.catch(err => {
res.send("Error posting to DB")
});
});
module.exports = router;
Here is my Express server:
const express = require('express');
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const authRoutes = require('./routes/api/auth');
const passportSetup = require('./config/passport-setup');
const cookieSession = require('cookie-session');
const keys = require('./config/keys');
const passport = require('passport');
const profileRoutes = require('./routes/api/profile-routes');
const bookRoutes = require('./routes/api/book-routes');
// Hooks up routes/api/items file
const items = require('./routes/api/items');
const app = express();
// Boderparser Middleware
app.use(bodyParser.json());
// sets up session cookies
app.use(cookieSession({
// Max age set to 1 day
maxAge: 24 * 60 * 60 * 1000,
// Uses cookieKey from keys file to encrypt
keys: [keys.session.cookieKey]
}));
// initialize passport
app.use(passport.initialize());
app.use(passport.session());
// DB Config
const db = require('./config/keys').mongoURI;
// Connect to mongodb
mongoose
.connect(db, { useNewUrlParser: true })
.then(() => console.log('MongoDB Connected'))
.catch(err => console.log(err));
// Use Routes, sets up routes/api/items to be used
app.use('/api/items', items);
app.use('/book', bookRoutes);
// Use auth.js's routes
app.use('/auth', authRoutes);
// Use profile-routes routes for profile page
app.use('/profile', profileRoutes);
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Server started on port ${port}`))
I'm unable to make a POST request and not sure why. The Express route handles some OAuth stuff and displays the logged in user's profile. On that same page I have the form which allows the user to add data and submit it. Is the logic from authCheck interfering with POSTing the form data? The router.post in my Express route does not successfully console.log anything.
I've seen people use Axios in the React form component itself to do a POST request. Is it better to do form POST requests with Axios or should I be handling it in the Express route?
You should use the axios for making the api call.
In your handleSubmit function you are using "event.preventDefault()" which will prevent the default behavior of the form.

Passportjs Local strategy never get called

I am learning passportjs and i have the following code in my server.js,the problem i am facing is that the passport.use('local',new LocalStrategy({}) in the below code is never called,the rest is working fine except for the localstrategy,been strugling with this for hours!!
I am learning passportjs and i have the following code in my server.js,the problem i am facing is that the passport.use('local',new LocalStrategy({}) in the below code is never called,the rest is working fine except for the localstrategy,been strugling with this for hours!!
const express=require("express");
const bodyParser=require('body-parser');
const ejs=require("ejs");
const cookieParser=require('cookie-parser');
const passport=require('passport');
const LocalStrategy=require('passport-local').Strategy;
const session=require("express-session");
const app=express();
app.set(express.static,'public');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(cookieParser());
app.use(session({secret:'library'}));
app.use(passport.initialize());
app.use(passport.session());
app.post('/auth/signUp',(req,res,next)=>{
console.log('body',req.body)
passport.authenticate('local',(err,user,info)=>{
console.log("whattt",user)
req.login(user,(err)=>{
res.redirect('/auth/profile');
});
})(req, res, next);
});
app.get('/auth/profile',(req,res)=>{
res.json(req.user);
});
app.get("/",async (req,res)=>{
res.render('index.ejs');
});
passport.serializeUser((user,done)=>{
done(null,user.id);
});
passport.deserializeUser((id, done)=> {
console.log("id",id);
let data=[{id:1,name:"malouda"},{id:2,name:"Jason"}];
let user = data.find((obj)=>{ return obj.id === id; });
done(null,user);
});
passport.use('local',new LocalStrategy({
usernameField: 'username',
passwordField: 'password'
},(username,password,done)=>{
user={id:1,name:"malouda"};
console.log("LocalStrategy")
done(null,user);
}));
app.listen(3000,()=>{
console.log("Listening on port 6000");
});
and in my index.js i have the following form
<form name="signUpForm" action="/auth/signUp" method="post" multipart='urlencoded'>
<div class="form-group">
<label for="username">Username</label>
<input type="text" class="form-control" name="username" id="username" placeholder="Username">
</div>
<div class="form-group">
<label for="exampleInputPassword1">Password</label>
<input type="password" class="form-control" name="password " id="exampleInputPassword1" placeholder="Password">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Passport LocalStrategy is used for login authentication.
In Signup, you don't need the passport. In Signup, you just create the user by storing it in the database.
You need to add
Passport.authenticate(`local`, (err, user, info) => {}
In your login API to authenticate the user.
As the name suggests, Passport.authenticate authenticates the user credentials. SO first you need to create the user.
Read more here.
Hope I cleared your thoughts.

Browser waiting on localhost on POST request

I'm building a website, and i have a registration form where i need to submit a form via POST, and register a user in a mongoDB databse. The website works fine so far, but when i submit the registration form the browser just "waits for localhost" forever. I use EJS as my templating engine, although i don't think that matters.
register.ejs:
<% include partials/header %>
<%include partials/nav %>
<h1>REGISTER</h1>
Login
<form id="registerForm" action="/register" method="post">
<div class="form-group">
<label for="exampleInputEmail1">Email address</label>
<input type="email" name="username" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Enter email">
<small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small>
</div>
<div class="form-group">
<label for="exampleInputPassword1">Password</label>
<input type="password" name="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
<small id="passwordHelp" class="form-text text-muted">Your password must be at least 8 characters long.</small>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<% include partials/footer %>
app.js:
var express = require('express'),
app = express(),
mongoose = require('mongoose'),
passport = require("passport"),
bodyParser = require("body-parser"),
User = require("./models/user"),
LocalStrategy = require("passport-local"),
passportLocalMongoose = require("passport-local-mongoose");
//Set up MongoDB
var mongo = require("mongo");
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var ObjectId = require('mongodb').ObjectID;
var url = 'mongodb://localhost:27017/customerapp';
//MongoJS
var mongojs = require("mongojs");
var db = mongojs("customerapp", ["users"]);
//Mongoose
var mongoose = require('mongoose');
mongoose.Promise = global.Promise
mongoose.createConnection("mongodb://localhost:27017/customerapp");
app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({extended: true}));
app.use(require("express-session")({
secret: "wah wah wah",
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
passport.use(new LocalStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
var index = require("./routes/index");
var about = require("./routes/about");
var login = require("./routes/login");
//var register = require("./routes/register");
app.all("index", index);
app.all("about", about);
app.all("login", login);
//app.all("register", register);
// AUTH Routes
//Register get request
app.get("/register", function(req, res) {
res.render("register");
});
//Handle post register req. at '/register'
app.post("/register", function(req, res) {
User.register(new User({
username: req.body.username}),
req.body.password,
function(err, user) {
if(err) {
console.log(err);
return res.render("register");
}
passport.authenticate("local")(req, res, function() {
res.redirect("/secret")
})
});
});
app.listen(process.env.PORT || 3000, process.env.IP, function () {
console.log('Example app listening on port 3000!')
})
You are using three params instead of two, use it like this.
//Handle post register req. at '/register'
app.post("/register", function(req, res) {
User.register(new User({
username: req.body.username,
password: req.body.password
}),
function(err, user) {
if(err) {
console.log(err);
return res.render("register");
}
passport.authenticate("local")(req, res, function() {
res.redirect("/secret")
})
});
});
Check to make sure your versions of mongoDB and mongoose are compatible. You can find a compatibility chart here.
In addition to checking your MongoDB and mongoose versions, you should also check if it's actually connecting to the database by using a callback function when you connect to the server, like so:
//Connecting to database using mongoose.connect with a callback
mongoose.connect("mongodb://localhost:27017/customerapp", function(error) {
if(error) {
console.log("There was an error connecting to MongoDB.");
console.log(error);
} else {
console.log("Successfully connected to MongoDB!");
}
});
This callback may also work with mongoose.createConnection instead of mongoose.connect, but I haven't tried. If neither message prints to the console, then the app is not getting any response from the server, not even an error.
For some reason, as long as mongoDB is running at all, GET requests still seem to work even if the connection attempt hangs, but POST requests run into trouble.
Source: Mongoose never connects to mongodb

why node.js bodyParser always returns 'undefined'?

In 'app.js' I have
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
'index.js' full codes
var express = require('express');
var router = express.Router();
var mysql = require('mysql');
router.get('/', function(req, res, next) {
res.render('index', { title: 'Here' });
});
router.post('/manager', function(req, res, next) {
var connection = mysql.createConnection({
host : 'localhost',
user : req.body.username,
password : req.body.password,
database : 'shops'
});
connection.connect(function(err){
if(!err)
res.render('manager', { title: 'Here' });
else
console.log("Error connecting database ...");
});
});
module.exports = router;
In 'index.html' login form
<form id='login' method='post' action='manager'>
Username<br>
<input id='username' type='text'><br>
Password<br>
<input id='password' type='password'><br>
<input type='submit' value='Login'>
<input type='reset' value='Reset'>
</form>
In index.js line 12-13
req.body.username
req.body.password
Everytime I try to parse data from html form, they return 'undefined'. I'm new to node.js scripting. Am I doing something wrong?
You're missing name attributes on your <input> tags. Add them like:
<form id='login' method='post' action='manager'>
Username<br>
<input id='username' name='username' type='text'><br>
Password<br>
<input id='password' name='password' type='password'><br>
<input type='submit' value='Login'>
<input type='reset' value='Reset'>
</form>

Resources