How to send maltipart/formdata from react to nodejs? - node.js

Hi I am new in MERN development world. I am trying develop my first MERN APP, till text input from browser I have created. Now I am stucked at the file input.
File field is working fine at frontend but in api the file field is empty but rest of the fields are working well...
In browser before api call photo/ file is there but in the api req.body or req.file no data.
I have used multer which is working fine.
Please help me, I trapped here.
Frontend Code
export const register = ({ name, email, password, password1, photo }) => (dispatch) => {
// Request body
const body = { name, email, password, password1, photo };
/*console.log(photo); //gives the desired output...*/
axios.post('/api/users/register', body)
.then(function (res) {
dispatch(returnStatus(res.data, res.status, 'REGISTER_SUCCESS'));
dispatch({ type: IS_LOADING })
})
.catch(function (err) {
dispatch(returnStatus(err.response.data, err.response.status, 'REGISTER_FAIL'))
dispatch({
type: REGISTER_FAIL
});
dispatch({ type: IS_LOADING })
});
};
Serverside code
exports.registerUser = (upload.single("photo"), (req, res) => {
const { name, email, password, password1 } = req.body;
console.log(req.file,req.body);
if(password != password1) return res.status(400).json("Passwords missmacth.");
const result = registerSchema.validate({ name, email, password});
if(!result.error) {
// Check for existing user
User.findOne({ email: email }).then((user) => {
if (user) return res.status(400).json("User already exists");
//New User created
const newUser = new User({
name,
email,
password,
password1
});
//Password hashing
bcrypt.genSalt(12, (err, salt) =>
bcrypt.hash(newUser.password, salt, (err, hash) => {
if (err) throw err;
newUser.password = hash;
bcrypt.hash(newUser.password1, salt, (err, hash) => {
if (err) throw err;
newUser.password1 = hash;
// Save user
newUser
.save()
.then(
res.json("Successfully Registered")
)
.catch((err) => console.log(err));
})
})
);
});
} else {
res.status(422).json(result.error.details[0].message);
}
});

Related

Reactjs: post data to localhost always pending

I am working on ReactJs and NodeJS and I am creating a signup page. I post data to server but it is always pending.
Which part did I do wrong? It would be nice if someone can help.
Front end:
const handleSubmit = (event) => {
// prevent page refresh
event.preventDefault();
const newUserData = {
name: name,
email: email,
password: password,
};
axios
.post("/signup", newUserData)
.then((res) => {
console.log(res.data);
})
.catch((error) => {
console.log(error);
});
setEmail("");
setName("");
setPassword("")
console.log("form submitted ✅");
};
Backend:
router.post("/signup", (req, res) => {
const { name, email, password } = req.body;
if (!email || !password || !name) {
res.status(422).send({ error: "Please add all the fields" });
}
console.log(req.body);
User.findOne({ email: email })
.then((savedUser) => {
if (savedUser) {
res.status(422).send({ error: "Email already been used" });
}
bcrypt.hash(password, 12).then((hashedpassword) => {
const user = new User({
name,
email,
password: hashedpassword,
});
user
.save()
.then((user) => {
res.json({ message: "Sign Up Successfully" });
})
.catch((err) => {
console.log(err);
});
});
})
.catch((err) => {
console.log(err);
});
});
in package.json i set proxy as
"proxy": "http://localhost:5000",
I guess you are using MongoDB as well, in that case keep in your mind that the findOne is async, so you need to use await before. And for to save data you need to use the .create() method from MongoDB, e.g.
router.post("/signup", async (req, res) => {
const { name, email, password } = req.body;
if (!email || !password || !name) {
res.status(422).send({ error: "Please add all the fields" });
}
console.log(req.body);
await User.findOne({ email: email })
.then((savedUser) => {
if (savedUser) {
// you need to add return to stop the code
return res.status(422).send({ error: "Email already been used" });
}
// or you can add else because the code keep running
bcrypt.hash(password, 12).then((hashedpassword) => {
const user = await User.create({
name,
email,
password: hashedpassword,
});
user
.save()
.then((user) => {
res.json({ message: "Sign Up Successfully" });
})
.catch((err) => {
console.log(err);
});
});
})
.catch((err) => {
console.log(err);
});
});
I think it is better to use something like throw new Error('Email already been used') instead of return for your res.status(422).send({ error: "Email already been used" }); because if you have return the server doesn't give back an error, but a normal answer, but of course it is ok if you want that.
I want you to be sure that before you submit, the values name, email, password, are updated. Please try:
const handleSubmit = async (event) => {
// prevent page refresh
event.preventDefault();
console.log(`The value for the name: ${name}`);
console.log(`The value for the email: ${email}`);
console.log(`The value for the password: ${password}`);
try {
const response = await axios.post("http://localhost:5000/signup", {
name,
email,
password,
});
console.log(response.data);
setEmail("");
setName("");
setPassword("");
console.log("form submitted ✅");
} catch (error) {
console.log(error);
}
};

Why my data cannot be saved into MongoDB?

I try to sign up, i submit the form then it logs me undefined, and it doesn't save the user into the database, even the code from the tutorial works perfectly.
Here's my code
exports.postSignup = (req, res, next) => {
const email = req.body.email;
const password = req.body.password;
const confirmPassword = req.body.confirmPassword;
User.findOne({ email: email })
.then(userDoc => {
if (userDoc) {
return res.redirect('/signup');
}
const user = new User({
email: email,
password: password,
cart: { items: [] }
});
return user.save();
})
.then(result => {
res.redirect('/login');
})
.catch(err => {
console.log(err);
});
};
I have to mention that the user model is correct.
Im not sure, but in my own code I dont save an object within the return line.
Maybe try this
exports.postSignup = (req, res, next) => {
const email = req.body.email;
const password = req.body.password;
const confirmPassword = req.body.confirmPassword;
User.findOne({ email: email })
.then(userDoc => {
if (userDoc) {
return res.redirect('/signup');
}
const user = new User({
email: email,
password: password,
cart: { items: [] }
});
try{
user.save();
}catch(err){
res.send(err);
}
return user; //only if you want to return a user ofc
})
Other things that maybe going on:
Is your ip whitelisted?
Did you include the connection string?
Do you return a jason object? then make sure to use a parser in your middleware.

error: data and hash arguments required for bcrypt. Incorrect MongoDB setup

I am trying to set up Passport with Express and MongoDB. At the moment I am able to register users in the database. But whenever I try to login, I get an error saying that data and hash arguments are required. Right now I have my Server.js file like this
const mongoose = require('mongoose');
const User = require('./models/users')
const initializePassport = require('./passport-config')
initializePassport(
passport,
email => User.find({email: email}),
id => User.find({id: id})
)
app.post('/register', checkNotAuthenticated, async (req, res) => {
try {
const hashedPassword = await bcrypt.hash(req.body.password, 10)
const newUser = new User({
id: Date.now().toString(),
name: req.body.name,
email: req.body.email,
password: hashedPassword
})
res.redirect('/login')
console.log(newUser)
} catch {
res.redirect('/register')
}
And my Passport-Config.js file like this `
const LocalStrategy = require('passport-local').Strategy
const bcrypt = require('bcrypt');
const User = require('./models/users')
function initialize(passport, getUserByEmail, getUserById) {
const authenticateUser = async (email, password, done) => {
const user = getUserByEmail(email)
if (user === null) {
return done(null, false, { message: 'No user with that email' })
}
try {
if (await bcrypt.compare(password, user.password)) {
return done(null, user)
} else {
return done(null, false, { message: 'Password incorrect' })
}
} catch (e) {
return done(e)
}
}
passport.use(new LocalStrategy({ usernameField: 'email' }, authenticateUser))
passport.serializeUser((user, done) => done(null, user.id))
passport.deserializeUser((id, done) => {
return done(null, User.findById({user: id}))
})
}
`
I've done some investigation using console.log() statements (not proud of it) but I think I've managed to find out the issue. If we add in the the first console log statement here:
app.post('/register', checkNotAuthenticated, async (req, res) => {
try {
console.log("BCRYPT COMPARE RUNS HERE")
const hashedPassword = await bcrypt.hash(req.body.password, 10)
const newUser = new User({
id: Date.now().toString(),
name: req.body.name,
email: req.body.email,
password: hashedPassword
})
res.redirect('/login')
console.log(newUser)
} catch {
res.redirect('/register')
}
and the second one here:
const initializePassport = require('./passport-config')
initializePassport(
passport,
email => User.find({email: email}).then((result) => { console.log("USER DATA EXTRACTED HERE") }).catch((err) => { console.log(err) }),
id => User.find({id: id})
)
The next time you click on login, you should see an output like:
Listening on port 3000
BCRYPT COMPARE HAPPENING
Error: data and hash arguments required
...
...
...
USER DATA EXTRACTED HERE
Notice that bcrypt.compare is being run before we are actually able to grab the user information from the DB? This means that all the arguments into that function are null, which is what is returning that error. Now, I'm no JS expert, but this can be fixed with an await statement added here:
function initialize(passport, getUserByEmail, getUserById) {
const authenticateUser = async (email, password, done) => {
const user = await getUserByEmail(email)
if (user === null) {
return done(null, false, { message: 'No user with that email' })
}
Which makes sure that the user info is queried from the DB before moving along in the script.

How can I improve error handling on a pool

I am have created a class User that will hold the logic for inserting a new user into a postresql database. My code works perfectly but i think it is poorly written and would like some views on how to improve it, especially error handling.
const pool = require('../config/config.js');
// user constructor
class User {
constructor(user) {
this.username = user.username;
this.email = user.email;
this.password = user.password;
this.role = user.role;
}
// save new user in databes
createUser(res) {
pool.connect((err, client, done) => {
done();
if (err) return res.status(400).json({ err });
client.query('INSERT INTO users (username, email, password, role) VALUES($1, $2, $3, $4)', [this.username, this.email, this.password, this.role], (error) => {
if (error) return res.json({ error });
return res.json({ message: 'created successfully' });
});
});
}
}
module.exports = User;
app.post('/', (req, res) => {
const user = new User({
username: 'Femoz',
password: '1234',
role: 'admin',
email: 'femoz#gmail.com',
});
user.createUser(res);
// res.json('user created successfully');
});
const pool = require('../config/config.js');
class User {
constructor(user) {
this.username = user.username;
this.email = user.email;
this.password = user.password;
this.role = user.role;
}
// save new user in databes
save(cb) {
const user = this;
// Perhaps, you should to do some checks of props e.g. a name is not empty
if (!user.name)
return cb(Error('Empty name'));
// I think that you should implement some wrapper
// e.g. `db.run` to avoid call the pool directly each time.
pool.connect((err, client, done) => {
// done(); here is an error. You released the db-connection too early.
if (err)
return cb(err);
// I assumed that the result of done() is undefined so cb will be called.
// Overwise use `&&` instead `||`.
client.query(
'INSERT INTO users (username, email, password, role) VALUES($1, $2, $3, $4) RETURNING id',
[user.username, user.email, user.password, user.role],
(err, res) => done() || cb(err, id: res && res.rows[0].id)
);
});
}
}
module.exports = User;
app.post('/', (req, res, next) => {
const user = new User({
username: 'Femoz',
password: '1234',
role: 'admin',
email: 'femoz#gmail.com',
});
// Return new id is better than a static text :)
user.save((err, id) => err ? res.status(400).json({error: err.message}) : res.json({id}));
// OR
// For Express you can pass error to an error handler
user.save((err, id) => err ? next(err) : res.json({id}));
});

can not register a new user

Back end i wrote in node.js and front end in react.js
I want to register a new User to my system.
Register worked if I used Postman, but register not worked at back end
Register.js(react.js):
axios.defaults.baseURL = 'http://localhost:5040';
axios.post('/users/register', newUser)
.then(res => console.log(res.data))
.catch(err => console.log(err.response.data));
newUser = {name: "test", email: "test0991#gmail.ru", password: "123456", password2: "123456"}
Back end:
router.post('/register', (req, res) => {
const { errors, isValid } = validateRegisterInput(req.body);
// Check Validation
if(!isValid){
return res.status(400).json(errors);
}
User.findOne({ email: req.body.email })
.then(user => {
if(user){
*
} else {
*
*
*
);
const newUser = new User({
*
*
*
*
});
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) =>{
if(err) throw err;
newUser.password = hash;
newUser.save()
.then(user => res.json(user))
.catch(err => console.log(err));
});
});
}
});
});
Error:
Unhandled Rejection (TypeError): Cannot read property 'data' of undefined
console.log(newUser);
axios.post('/users/register', newUser)
.then(res => console.log(res.data))
.catch(err => console.log(err.res.data));
Perhaps you are not sending data. For some reason you use newUser when calling axios.post(), but you don't assign newUser a value until after calling axios.post(). The order should be swapped, like this:
axios.defaults.baseURL = 'http://localhost:5040';
newUser = {name: "test", email: "test0991#gmail.ru", password: "123456", password2: "123456"}
axios.post('/users/register', newUser)
.then(res => console.log(res.data))
.catch(err => console.log(err.response.data));

Resources