How to handle promise handing error in mysql? (Debian, VMWARE) - mysql

So I am trying to use implement argon2 in my login application which uses a MySQL database. I have managed to store the username and its hashed password in the database while receiving a promise handling error. But I am unable to login with the same username and password by passing parameters via Postman since I get the same error.
Here is my code so far:
server.js
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
app.use(bodyParser.json({ type: "application/json" }));
app.use(bodyParser.urlencoded({ extended: true }));
app.set("port", 8080);
const argon2 = require("argon2");
const Pool = require("mysql2").createPool;
const config = {
host: "localhost",
user: "root",
password: "XXXXX",
database: "XXXXX"
};
const pool = new Pool(config);
app.post("/login", async (req, res) => {
console.log(req.body);
const username = req.body.username;
const password = req.body.password;
try {
const query = "SELECT password from adminlogin where username = ?";
const result = await pool.query(query, [username]);
if (result.rowCount == 1) {
console.log(result.rows[0].password);
if (await argon2.verify(result.rows[0].password, password)) {
res.json("Log In successful");
} else {
res.json("Password incorrect");
}
} else {
res.json("username not found");
}
} catch (err) {
console.log("ERROR " + err);
}
});
app.post("/create", async (req, res) => {
let hash;
const username = req.body.username;
const password = req.body.password;
try {
hash = await argon2.hash(password, "abcdefghijklmnop");
console.log("HASH " + hash);
const query = "INSERT INTO adminlogin (username, password) VALUES (?, ?)";
const result = await pool.query(query, [username, hash]);
//console.log(result);
if (result.rowCount == 1) {
res.json("User created");
} else {
res.json("User not created");
}
} catch (err) {
console.log("ERROR " + err);
if (err.message.search("duplicate") != -1) {
res.json("Username taken");
}
}
});
Error Messages:
You have tried to call .then(), .catch(), or invoked await on the result of query that is not a promise, which is a programming error. Try calling con.promise().query(), or require('mysql2/promise') instead of 'mysql2' for a promise-compatible version of the query interface. To learn how to use async/await or Promises check out documentation at https://www.npmjs.com/package/mysql2#using-promise-wrapper, or the mysql2 documentation at https://github.com/sidorares/node-mysql2/tree/master/documentation/Promise-Wrapper.md
ERROR Error: You have tried to call .then(), .catch(), or invoked await on the result of query that is not a promise, which is a programming error. Try calling con.promise().query(), or require('mysql2/promise') instead of 'mysql2' for a promise-compatible version of the query interface. To learn how to use async/await or Promises check out documentation at https://www.npmjs.com/package/mysql2#using-promise-wrapper, or the mysql2 documentation at https://github.com/sidorares/node-mysql2/tree/master/documentation/Promise-Wrapper.md

The problem is you are using the MySQL npm package and it doesn't return any promises when you are using the pool.query(), it returns a callback. I have faced the same situation. Try to use it as a traditional callback function like pool.query(query, [username], (err, result)=>{}). and return the result as callback within that function. Hope this will be helpful for you.

Related

In node.js, How to return mysql results from a function?

I tried to separate function to another file, as the function fetching data from mysql database.
This is db.js
const mysql = require('mysql');
var con = mysql.createConnection({
host: "localhost",
user: "root",
password: "",
database: "sample"
});
con.connect()
module.exports = function(query) {
con.query(query, function (err, result) {
if (err){
console.log(err);
} else{
console.log(result)
return result
}
});
};
This is main.js
const express = require('express')
const db = require('./db')
const app = express()
app.get('/test', function(req, res){
var sql = "SELECT id FROM user"
console.log(db(sql))
res.send(db(sql))
});
In main.js on console.log(db(sql)) got undefined.
But in db.js on console.log(result) I got the values as:
[
RowDataPacket { id: 1 },
RowDataPacket { id: 2 },
RowDataPacket { id: 3 }
]
Why did I get undefined in the main.js? Is there any solution for this issue?
Since you are using callback function, you can't directly return the value from it.
you have 2 options to do what you want to do.
Promise
Async/Await (mysql2 module needed)
Try this,
Querying
function(query) {
return new Promise((resolve, reject) =>{
try{
con.query(query, function (err, result) {
if (err){
return reject(err)
}
return resolve(result)
});
}
catch(e){
reject(e)
}
})
};
Main
app.get('/test', async function(req, res){
var sql = "SELECT id FROM user"
try{
const userId = await db(sql)
return res.send({
success: true,
result: {
userId
}
})
}
catch(e){
console.error(e)
return res.status(500).send({
success: false,
message: 'internal server error'
})
}
})
One more thing, if you have a good reason to write query by yourself, you can use
knex for making it easier (https://www.npmjs.com/package/knex), which is a query builder, meaning doing nothing to do with database connection.
Sollution
Try async/await with mysql2
Dont go for mysql2/primse because it will cause unexpected errors when your database is in the cloud or deployed somewhere like clearDB addons provided by Heroku
Follow these steps...
create config file for your database connection seperately
import mysql from 'mysql2'
let db = mysql.createPool({
host: 'your host name',
user: "your username",
password: "your password",
database: "your database name",
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
})
export { db }
execute the query the same like this i am doing
import {db} from 'where you defined the above db config'
app.get('/test', async function(req, res){
const promise= db.promise()
var sql = "SELECT id FROM user"
const [rows,field] = awiat promise.execute(sql)
res.send(rows)
});

Node JS MySQL wait for results

I'm quite new to Node JS, and I'm trying to build an API based on MySQL.
In one of my routers I'm trying to inject an insert query and based on it, get the new generated task id from mysql.
The problem is that the second query is not waiting for the response and sometimes I'm getting an error because taskId variable is undefined because it still didn't get the results from the first query.
the problematic variable that is not getting it's value correctly is taskId.
I'm attaching my code for your review, thanks for your help!
As requested: I'm attaching my required moudle as well:
const dotenv = require('dotenv');
const mysql = require('mysql');
dotenv.config();
var connection = mysql.createPool({
host: process.env.DB_HOST,
user: process.env.DB_USERNAME,
password: process.env.DB_PASSWORD,
database: process.env.DB_TABLE,
port: process.env.DB_PORT
});
module.exports = connection;
router.post('/new', auth, async (req, res) => {
const uid = req.body.uid;
const taskName = req.body.taskName;
const description = req.body.description;
const createdDate = req.body.createdDate;
const estimatedDate = req.body.estimatedDate;
const status = req.body.status;
let taskId = '';
addTaskQuery = `INSERT INTO task (title,description,status) VALUES ('${taskName}','${description}','${status}')`;
findTaskIdQuery = `SELECT id FROM task WHERE title = '${taskName}'`;
try {
// Injecting into task table
await connection.query(addTaskQuery, (err, results) => {
if(err) {
console.log(err);
return res.send(JSON.stringify({data: err}));
}
})
// Getting the new inserted task id
await connection.query(findTaskIdQuery, (err, results) => {
if(err) {
console.log(err);
return res.send(JSON.stringify({data: err}));
}
taskId = JSON.stringify(results[0].id);
})
// Injecting into havetask table
await connection.query(`INSERT INTO havetask (id,userId,taskId) VALUES (${taskId},${uid},${taskId})`, (err, results) => {
if(err) {
console.log(err);
return res.send(JSON.stringify({data: err}));
}
})
}
catch(err) {
console.log(err);
return res.status(401).json({ msg: 'An error occured while tried to add task'});
}
})
The mysql package you use does not support Promises (=== it doesn't do async / await). So your await statements don't wait, they just fall through.
You need to try a package that handles async / await. This one might do the trick.

Angular HTTPClient (HTTP) requests pending forever

I have recently started working with MySQL as the database for my Angular/NodeJS project (I have been using MongoDB all along). Nonetheless, I'm encountering issues when handling HTTP Requests. I have experimented with GET and POST requests as of now, and GET is forever pending, until failure and POST doesn't post to backend and to the database, likewise. I really hadn't changed the backend configuration from the one I used with MongoDB database, except for the queries, of course.
I have tried debugging the backend to check whether the server is actually running and everything was okay. It just came to requests reaching the specified endpoints that they're always pending. I also tried to log to console if a request gets at a certain endpoint, but nothing was being logged, unfortunately.
server.js
const app = require("./backend/app");
const debug = require("debug")("node-angular");
const http = require("http");
const normalisePort = setPort => {
const port = parseInt(setPort, 10);
if (isNaN(port)) return setPort;
if (port >= 0) return port;
return false;
};
const port = normalisePort(process.env.PORT || "8000");
const server = http.createServer(app);
const error = error => {
if (error.syscall !== "listen") {
throw error;
}
const bind = typeof port === "string" ? "pipe " + port : "port " + port;
switch (error.code) {
case "EACCES":
console.error(bind + " requires elevated privileges");
process.exit(1);
break;
case "EADDRINUSE":
console.error(bind + " is already in use");
process.exit(1);
break;
default:
throw error;
}
};
const listening = () => {
const address = server.address();
const bind = typeof port === "string" ? "pipe " + address : "port " + port;
debug.enabled = true;
debug("Listening on " + bind);
};
app.set("port", port);
server.on("error", error);
server.on("listening", listening);
server.listen(port, "localhost");
app.js
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const users = require("./routes/users");
const app = express();
app.use(cors);
app.use(bodyParser.json());
app.use(
bodyParser.urlencoded({
extended: false
})
);
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Authorization, Content-Type, Accept"
);
res.setHeader(
"Access-Control-Allow-Methods",
"GET, POST, PATCH, DELETE, OPTIONS"
);
next();
});
app.get("/api/users", users);
module.exports = app;
users.js
const express = require("express");
const router = express.Router();
const db = require("../sql-connection");
router.get("", (req, res, next) => {
db.query("select * from users;", (error, results, fields) => {
if (results.length > 0) {
return res.status(200).send(results);
} else {
return res.status(404).send();
}
});
});
module.exports = router;
sql-connection.js
const mysql = require("mysql");
const sqlConnection = mysql.createConnection({
host: "localhost",
user: "root",
password: "",
database: "payroll"
});
sqlConnection.connect(error => {
if (error) throw error;
console.log("connected to database");
});
module.exports = sqlConnection;
auth.service.ts
export class AuthService {
private _BASE_URL: string = "http://localhost:8000/api";
constructor(private http: HttpClient) {}
public get users(): Observable<any> {
return this.http.get(this._BASE_URL + "/users");
}
}
signup.component.ts
export class SignUpComponent {
constructor(private _authService: AuthService) {}
public onSignUp(): void {
this._authService
.users()
.subscribe(data => (data ? console.log(data) : console.log("no data")));
}
}
When subscribed to the users observable data from backend should logged to console if present, otherwise, 'no data' is logged on the console. Unfortunately, this request takes forever (pending). However, if I don't subscribe to users no request is sent/seen under network tab in dev tools.
I've been using MYSQL database and I would recommend using mysql2 over mysql
mysql2 provides promise based syntaxes over conventional callback methods.
Here's the documentation for Mysql2 for nodejs.
Coming to the problem, I guess it might be because Nodejs is asynchronous while you're using a synchronous approach in setting up the API.
Also when you're working with Asynchronous programming you have to use try-catch-finally instead of conventional if-else statements to log the errors.
So you can use async (req, res, next)=>{ //your code here } rather than just using (req, res, next)=>{ //your code here }.
Also you have to await before calling the sql query, i.e;
await db.query
or
rather in mysql2 it is easier to use const [data] = await pool.execute(query, [params]).

Extracting information from reddit json and placing it in mysql database using node.js

I'm trying to extract JSON data from /r/askreddit and put it in a mysql database table called "post". The columns in the table are information such as the title of the post, url of the post, and the username of the poster.
I'm at a complete loss at this point on how to bring the data from the raw JSON into my table from the raw JSON, as I thought it should now be working.
Here is my .js server file, any help is appreciated. Thanks.
/*jshint esversion: 6 */
let mysql = require('mysql2');
let dbInfo = require('./dbInfo.js');
let express = require('express');
let bodyParser = require("body-parser");
let app = express();
// Add static route for non-Node.js pages
app.use(express.static('public'));
// Configure body parser for handling post operations
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.post('/reddit-import', function (req, res) {
console.log("Route for the /r/askreddit POST");
let sql = for (let i=0; i < x.data.children.length; i++) {
"insert into post (post_title, post_date, post_url, user_name) values (?,?,?,?)"
};
let data = [req.body.post_title, req.body.post_date, req.body.post_url, req.body.user_name];
connection.query(sql,
data,
function (errQuery, result) {
if (errQuery) {
console.log(errQuery);
res.json({status: "Error", err: errQuery});
} else {
console.log("Insert ID: ", result.insertId);
res.json({status: result.insertId, err: ""});
}
}
);
});
// Create database connection
console.log('Creating connection...\n');
let connection = mysql.createConnection({
host: dbInfo.dbHost,
port: dbInfo.dbPort,
user: dbInfo.dbUser,
password: dbInfo.dbPassword,
database: dbInfo.dbDatabase
});
// Connect to database
connection.connect(function(err) {
console.log('Connecting to database...\n');
// Handle any errors
if (err) {
console.log(err);
console.log('Exiting application...\n');
} else {
console.log('Connected to database...\n');
// Listen for connections
// Note: Will terminate with an error if database connection
// is closed
const ip = 'localhost';
const port = 8080;
app.listen(port, ip, function () {
try {
console.log('Alumni server app listening on port ' + port);
} catch (err) {
console.log(err);
}
});
}
});

How to provide a mysql database connection in single file in nodejs

I need to provide the mysql connection for modules. I have a code like this.
var express = require('express'),
app = express(),
server = require('http').createServer(app);
var mysql = require('mysql');
var connection = mysql.createConnection({
host : '127.0.0.1',
user : 'root',
password : '',
database : 'chat'
});
connection.connect(function(err) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
}
});
app.get('/save', function(req,res){
var post = {from:'me', to:'you', msg:'hi'};
var query = connection.query('INSERT INTO messages SET ?', post, function(err, result) {
if (err) throw err;
});
});
server.listen(3000);
But how we provide one time mysql connection for all the modules.
You could create a db wrapper then require it. node's require returns the same instance of a module every time, so you can perform your connection and return a handler. From the Node.js docs:
every call to require('foo') will get exactly the same object returned, if it would resolve to the same file.
You could create db.js:
var mysql = require('mysql');
var connection = mysql.createConnection({
host : '127.0.0.1',
user : 'root',
password : '',
database : 'chat'
});
connection.connect(function(err) {
if (err) throw err;
});
module.exports = connection;
Then in your app.js, you would simply require it.
var express = require('express');
var app = express();
var db = require('./db');
app.get('/save',function(req,res){
var post = {from:'me', to:'you', msg:'hi'};
db.query('INSERT INTO messages SET ?', post, function(err, result) {
if (err) throw err;
});
});
server.listen(3000);
This approach allows you to abstract any connection details, wrap anything else you want to expose and require db throughout your application while maintaining one connection to your db thanks to how node require works :)
I took a similar approach as Sean3z but instead I have the connection closed everytime i make a query.
His way works if it's only executed on the entry point of your app, but let's say you have controllers that you want to do a var db = require('./db'). You can't because otherwise everytime you access that controller you will be creating a new connection.
To avoid that, i think it's safer, in my opinion, to open and close the connection everytime.
here is a snippet of my code.
mysq_query.js
// Dependencies
var mysql = require('mysql'),
config = require("../config");
/*
* #sqlConnection
* Creates the connection, makes the query and close it to avoid concurrency conflicts.
*/
var sqlConnection = function sqlConnection(sql, values, next) {
// It means that the values hasnt been passed
if (arguments.length === 2) {
next = values;
values = null;
}
var connection = mysql.createConnection(config.db);
connection.connect(function(err) {
if (err !== null) {
console.log("[MYSQL] Error connecting to mysql:" + err+'\n');
}
});
connection.query(sql, values, function(err) {
connection.end(); // close the connection
if (err) {
throw err;
}
// Execute the callback
next.apply(this, arguments);
});
}
module.exports = sqlConnection;
Than you can use it anywhere just doing like
var mysql_query = require('path/to/your/mysql_query');
mysql_query('SELECT * from your_table where ?', {id: '1'}, function(err, rows) {
console.log(rows);
});
UPDATED:
config.json looks like
{
"db": {
"user" : "USERNAME",
"password" : "PASSWORD",
"database" : "DATABASE_NAME",
"socketPath": "/tmp/mysql.sock"
}
}
Hope this helps.
I think that you should use a connection pool instead of share a single connection. A connection pool would provide a much better performance, as you can check here.
As stated in the library documentation, it occurs because the MySQL protocol is sequential (this means that you need multiple connections to execute queries in parallel).
Connection Pool Docs
From the node.js documentation, "To have a module execute code multiple times, export a function, and call that function", you could use node.js module.export and have a single file to manage the db connections.You can find more at Node.js documentation. Let's say db.js file be like:
const mysql = require('mysql');
var connection;
module.exports = {
dbConnection: function () {
connection = mysql.createConnection({
host: "127.0.0.1",
user: "Your_user",
password: "Your_password",
database: 'Your_bd'
});
connection.connect();
return connection;
}
};
Then, the file where you are going to use the connection could be like useDb.js:
const dbConnection = require('./db');
var connection;
function callDb() {
try {
connection = dbConnectionManager.dbConnection();
connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
if (!error) {
let response = "The solution is: " + results[0].solution;
console.log(response);
} else {
console.log(error);
}
});
connection.end();
} catch (err) {
console.log(err);
}
}
var mysql = require('mysql');
var pool = mysql.createPool({
host : 'yourip',
port : 'yourport',
user : 'dbusername',
password : 'dbpwd',
database : 'database schema name',
dateStrings: true,
multipleStatements: true
});
// TODO - if any pool issues need to try this link for connection management
// https://stackoverflow.com/questions/18496540/node-js-mysql-connection-pooling
module.exports = function(qry, qrytype, msg, callback) {
if(qrytype != 'S') {
console.log(qry);
}
pool.getConnection(function(err, connection) {
if(err) {
if(connection)
connection.release();
throw err;
}
// Use the connection
connection.query(qry, function (err, results, fields) {
connection.release();
if(err) {
callback('E#connection.query-Error occurred.#'+ err.sqlMessage);
return;
}
if(qrytype==='S') {
//for Select statement
// setTimeout(function() {
callback(results);
// }, 500);
} else if(qrytype==='N'){
let resarr = results[results.length-1];
let newid= '';
if(resarr.length)
newid = resarr[0]['#eid'];
callback(msg + newid);
} else if(qrytype==='U'){
//let ret = 'I#' + entity + ' updated#Updated rows count: ' + results[1].changedRows;
callback(msg);
} else if(qrytype==='D'){
//let resarr = results[1].affectedRows;
callback(msg);
}
});
connection.on('error', function (err) {
connection.release();
callback('E#connection.on-Error occurred.#'+ err.sqlMessage);
return;
});
});
}
try this
var express = require('express');
var mysql = require('mysql');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', routes);
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
console.log(app);
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
var con = mysql.createConnection({
host: "localhost",
user: "root",
password: "admin123",
database: "sitepoint"
});
con.connect(function(err){
if(err){
console.log('Error connecting to Db');
return;
}
console.log('Connection established');
});
module.exports = app;
you can create a global variable and then access that variable in other files.
here is my code, I have created a separate file for MySQL database connection called db.js
const mysql = require('mysql');
var conn = mysql.createConnection({
host: "localhost",
user: "root",
password: "xxxxx",
database: "test"
});
conn.connect((err) => {
if (err) throw err;
console.log('Connected to the MySql DB');
});
module.exports = conn;
Then in the app.js file
const express = require('express');
const router = express.Router();
// MySql Db connection and set in globally
global.db = require('../config/db');
Now you can use it in any other file
const express = require('express');
const router = express.Router();
router.post('/signin', (req, res) => {
try {
var param = req.body;
var sql = `select * from user`;
// db is global variable
db.query(sql, (err, data) => {
if (err) throw new SyntaxError(err);
res.status(200).json({ 'auth': true, 'data': data });
});
} catch (err) {
res.status(400).json({ 'auth': false, 'data': err.message });
}
});