I have the following Node/Express route which is used to post data to a MySQL server. It first adds a new user to a table and then takes the id of the new user and adds some more info to a profile table. The second query is dependent on the first one so they run sequentially.
I have written the following code and it runs correctly and does the job.
routes.post('/register', (req,res) => {
console.log('api req: ', req.body)
const email = req.body.email
const password = 'test'// req.body.password
if (!email || !password) return res.status(400).json({type: 'error', message: 'Please provide email and password'})
const hash = bcrypt.hash(password, 10)
// console.log('hash is ...', hash )
var sqlquery = "INSERT INTO user (username, first_name, last_name, email, password) VALUES ('test#gmail.com', 'Dan', 'Brown', 'test#gmail.com', 'test')"
db.query(sqlquery, (error, results) => {
if (error) return res.status(400).json({type: 'error', message: error})
if (results.length == 0) {
// do something
} else {
// run another query based on results from previous query
var profilequery = "INSERT INTO userprofile (user_id, address, age) VALUES (" + results.insertId + ", 'test address', 25)"
db.query(profilequery, (error1, results1) => {
if (error) return res.status(400).json({type: 'error1', message: error1})
console.log("profile inserted, ID: " + results1)
})
}
console.log("1 record inserted, ID: " + results.insertId);
res.json({type: 'success', message: 'user registered', results})
return results
})
})
There are two problems:
Problem 1: This code is not asynchronous. I would love to use async/await on this code. Really appreciate if someone can help me convert this into async code.
Problem 2: I have tried to use bcrypt to hash the password. However, if I use the hashed value in the query, the query fails because bcrypt returns a promise and not the actual hashed password. I do I resolve this.
not tested:
asyncQuery = (query, args) => {
return new Promise((resolve, reject) => {
db.query(query, function (err, result, fields) {
if (err)
return reject(err);
resolve(result);
});
});
}
routes.post('/register', (req, res) => {
console.log('api req: ', req.body)
const email = req.body.email
const password = 'test'// req.body.password
if (!email || !password) return res.status(400).json({ type: 'error', message: 'Please provide email and password' })
const hash = bcrypt.hash(password, 10)
// console.log('hash is ...', hash )
const sqlquery = "INSERT INTO user (username, first_name, last_name, email, password) VALUES ('test#gmail.com', 'Dan', 'Brown', 'test#gmail.com', 'test')"
let firstresult, secondresult;
asyncQuery(sqlquery)
.then(rows => {
firstresult = rows;
const profilequery = `INSERT INTO userprofile (user_id, address, age) VALUES ("${rows.insertId}", 'test address', 25)`;
return asyncQuery(profilequery)
})
.then(rows => {
secondresult = rows;
})
.then( () => {
console.log(`firstresult:${firstresult}`)
console.log(`firstresult:${secondresult}`)
res.json({ type: 'success', message: 'user registered', results })
})
.catch(rows => {
console.log(`Error:${rows}`)
})
})
Related
How can i do this, When a user registers , I would like the endpoint to still go ahead and get back the information which is saved inside the database.For some reason, it does not work as expected
How do i go about this :
My code is looking thus :
app.post("/api/sign-up", async function (req, res) {
dbConn.query(
`select * from accounts where email = ${dbConn.escape(req.body.email)}`,
async function (err, result, fields) {
if (result.length === 0) {
var email = req.body.email;
var phone = req.body.phone;
var password = req.body.password;
var fullname = "NULL";
const hashPass = await bcrypt.hash(password, 12);
dbConn.query(
`insert into accounts(email, phone, password, fullname) values (?,?,?,?)`,
[email, phone, hashPass, fullname],
function (error, results, fields) {
if (error) throw error;
return res.send({
error: false,
data: results[0],
message: "User created Successfully",
});
}
);
} else {
return res.send({
error: true,
message: "User exists",
});
}
}
);
});
Checked thru the internet, i could not find the information needed.
I managed to fix it.
Code looks like this now , and it shows the data inside POST man
app.post("/api/sign-up", async function (req, res) {
dbConn.query(
`select * from accounts where email = ${dbConn.escape(req.body.email)}`,
async function (err, result, fields) {
if (result.length === 0) {
var email = req.body.email;
var phone = req.body.phone;
var password = req.body.password;
var fullname = "NULL";
const hashPass = await bcrypt.hash(password, 12);
dbConn.query(
`insert into accounts(email, phone, password, fullname) values (?,?,?,?)`,
[email, phone, hashPass, fullname],
function (error, results, fields) {
if (error) throw error;
return res.send({
error: false,
email:email,phone:phone,
message: "User created Successfully",
});
//return res.status(201).json({message: 'User created Successfully', "email":email,"phone":phone});
}
);
} else {
return res.send({
error: true,
message: "User exists",
});
}
}
);
});
Thanks to everyone who decided to take a Look :)
permission to ask the temperature, so I use NodeMailer to send data email, the problem is that emails that are not registered in the database can still send the data. registered"
const sendMail = async (req, res) => {
const querySearch = 'SELECT * FROM user WHERE email="' + req.body.email + '"';
const email = req.body.email;
koneksi.query(querySearch, async (err, rows, field) => {
const random = require("simple-random-number-generator");
let params = {
min: 0000,
max: 9999,
integer: true
};
const CodeRandom = random(params);
const querySql = 'UPDATE user SET ? WHERE email = ?';
koneksi.query(querySql, [{ code_verification: CodeRandom, }, req.body.email], (err, rows, field) => {
// error handling
if (err) {
return res.status(500).json({ message: 'Gagal update code!', data: { code_verification: "" } });
}
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: '***********#gmail.com',
pass: '*********'
}
});
const mailOptions = {
from: 'muthiazraihan27#gmail.com',
to: req.body.email,
subject: 'Kode Verifikasi Lupa Password',
html: '<h2>Berikut kode reset password anda:</h2><h1> ' + CodeRandom + '</h1> '
};
transporter.sendMail(mailOptions, (err, info) => {
if (err) {
console.log(err)
res.status(500).json({ message: 'Ada kesalahan', error: err })
} else {
res.status(200).json({
success: true, data: rows[0]
})
}
})
})
})
};
in order to answer my question
When I insert data into my DB it says that it was successful but upon checking my DB, all of my fields are null. I am getting undefined values on my firstName,lastName, mobile, and email columns.
I'm really having a hard time debugging as I'm pretty new to JS. I hope anyone can point out what's the problem.
This is the model for Guest
var Guest = function(guest) {
this.firstName = guest.firstName;
this.lastName = guest.lastName;
this.mobile = guest.mobile;
this.email = guest.email;
}
// Insert Guest Data to DB
Guest.createGuest = (guestRequestData, result) => {
db.query('INSERT INTO guest SET ? ', guestRequestData, (error, response) => {
if(error){
console.log('Error while inserting data');
result(null, error);
}else{
console.log('Guest created successfully');
result(null, response);
}
})
}
module.exports = Guest;
And this the controller
// Create New Guest
exports.createNewGuest = (request, response) => {
const guestRequestData = new GuestModel(request.body);
console.log('Request Data', guestRequestData);
// Check Null
if(request.body.constructor === Object && Object(request.body).length === 0){
response.send(400).send({success: false, message: 'Please fill all fields'});
}else{
GuestModel.createGuest(guestRequestData, (error, guest) => {
if(error)
response.send(error);
response.json({status: true, message: 'Guest Created Successfully', data: guest.insertId})
})
}
}
There is a clear example how to insert data into MySQL database using node.js: https://www.mysqltutorial.org/mysql-nodejs/insert/
So in your case would look something like this:
db.query('INSERT INTO guest (firstName, lastName, mobile, email) VALUES (?, ?, ?, ?)', guestRequestData, (error, response) => {
if(error){
console.log('Error while inserting data');
result(null, error);
}else{
console.log('Guest created successfully');
result(null, response);
}
})
where the guestRequestData has the following structure:
["Your first name", "Your last name", "Your mobile", "Your email"]
Make sure you convert the guestRequestData to this format.
I wanted to made a query to the mysql database if the username already exists he should throw me a message and if not, show me the new id. I wanted to check if the query result.lenght is higher than 0.
however it throws the error "Cannot read property 'length' of undefined"
Service file
const connect = () =>
mysql.createConnection({
host: process.env.MYSQL_HOST,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE
});
const insert = (conn, user) => {
return conn.query(`insert into user(username, firstName, lastName, password)
values(?,?,?,?)`,
[
user.username,
user.firstName,
user.lastName,
user.password
]
)
}
const getByUsername = username => {
return connect()
.then(conn => {
conn.query(
`select id, username, firstName, lastName
from user
where username = ?`,
[username]
);
})
}
const create = user => {
return getByUsername(user.username)
.then(result => {
if (result.length > 0) {
throw new Error(`User "${user.username}" already exists`);
}
})
.then(() => connect())
.then(conn => insert(conn, user))
.then(result =>
({
id: result.insertId
}));
};
Controller file
const create = (req, res) => {
userService.create(req.body)
.then(result => {
res.status(200);
res.json(result);
})
.catch(err => {
res.status(500);
res.send('Error ' + err.message);
})
}
I tried to define lenght but I think this isnt the issue. I make the query with postman and i use mysql as database. I also tried to replace the result.length with username.length but it thorws "Error username is not defined"...
The result might be undefined there. Because we don't return proper query results. That why we getting error.
Solution:
const getByUsername = username => {
return new Promise((resolve, reject) => {
connect()
.then(conn => {
conn.query(
`select id, username, firstName, lastName
from user
where username = ?`,
[username],
function(err, results) {
if (err) {
return reject(err);
}
return resolve(results)
}
);
})
});
}
Explanation:
As per mysql2 documentation, the conn.query will not return the results. The conn.query method has a third argument which is a callback method. Here we can get the SQL query error and query results.
By the use of javascript Promise API, we can decide to reject or resolve based upon the SQL query result.
Although I have a successful insert I get an error (TypeError: res.json is not a function) when I want to return a json message upon. This is my setup:
const express = require('express');
module.exports = {
signup: async (req, res, next) => {
const { email, username, password } = req.value.body;
const connection = require('../config/dbconnection');
connection.query("SELECT * FROM tbl_users WHERE email = ?",[email], function(err, rows) {
if (rows.length) {
return res.json({ err: 'Email already exist'});
} else {
var newUserMysql = {
email: email,
username: username,
password: password
};
var insertQuery = "INSERT INTO tbl_users ( email, username, password ) values (?,?,?)";
connection.query(insertQuery,[newUserMysql.email, newUserMysql.username, newUserMysql.password],function(err, res, rows) {
if(err){
console.log('Insert error');
//res.json({ err: 'Insert error'});
} else {
console.log('Insert successful');
return res.json({ 'success': 'Insert successful'});
//return done(null, newUserMysql);
}
});
}
});
}
How can I return a json on successfull insert?
Your function's res parameter is hidden by the res return value from the connection.query call.
Rename the res parameter of this call to result (for example) and you should be fine:
connection.query(insertQuery,[newUserMysql.email, newUserMysql.username, newUserMysql.password],function(err, result, rows) {
if(err){
console.log('Insert error');
//res.json({ err: 'Insert error'});
} else {
console.log('Insert successful');
return res.json({ 'success': 'Insert successful'});
//return done(null, newUserMysql);
}
});
When you have nested scopes with conflicting variable names, the variable the closest (scope-wise) from where you reference this conflicting name will be used.
You're redefining res in your connection.query(insertQuery, [.....], function(err, res, rows) { ...}) function.
That res overrules the res from your express router within the scope of that function