I am new to Nodejs.I want to convert this code to promises (nodejs).This includes four callback function get(),abc1(),pqr(),xyz(). It gives error of "cannot read property 'then' of undefined" Can anyone fix it? I am trying it to convert into promises from this example here
var jwt = require('jwt-simple');
var mysql = require('mysql');
var async = require('async');
var Promise = require('bluebird');
var connection = mysql.createConnection({
host: 'localhost',
port: 3306,
database: 'abc',
user: 'root',
password: ''
});
var auth = {
login: function (req, res) {
var username = req.body.username || '';
var password = req.body.password || '';
console.log(req.body);
//This is get() function
function get(err, rows) {
connection.connect(function (err) {
if (err) {
console.error('error connecting: ' + err.stack);
return;
} else {
console.log("connected to database");
connection.query("SELECT count(id) as count from abc where name=? AND email=?", [username, password], function (err, rows) {
if (err) {
throw err
} else {
b = rows;
console.log(b);
}
});
}
});
}
//this is abc1() function
function abc1(err, rows) {
console.log("onresult");
if (err) {
throw err;
console.log("error in Query");
} else {
if (rows[0].count != 1) {
//xyz(result,xyz);
res.json({
"status": 401,
"message": "Invalid credentials"
});
} else {
connection.query("SELECT email from abc where name=? AND email=?", [username, password], function (err, rows) {});
//res.json(genToken("ayush"));
}
}
}
//This is xyz() function
function xyz(err, rows) {
if (err) {
console.log(err);
}
console.log(rows);
connection.query("SELECT name from abc where name=? AND email=?", [username, password], function (err, rows) {});
}
//This is pqr() Function
function pqr(err, rows) {
if (err) {
console.log(err);
}
console.log(rows);
}
get()
.then(function (rows) {
// do something...
//console.log("hellow1");
return abc1();
})
.then(function (rows) {
// do something...
console.log("hellow2");
return xyz();
})
.then(function (rows) {
// the third and final async response
console.log("hellow3");
return pqr();
})
.then(function (rows) {
// the third and final async response
console.log("hellow4");
})
.fail(function (err) {
// handle any error resulting from any of the above calls
throw err;
})
.done();
}
}
With arguments (err, rows), all four functions appear to be written as nodebacks and we can make a shrewd guess as to what the original working code looked like.
Without modification, nodebacks can only be used as nodebacks. Inserting them raw into a promise chain won't work.
But your functions will work in a promise chain after :
Promisifying the underlying asycn functions, ie connection's methods.
Calling, in the functions, the connection.methodAsync() version of the methods instead of connection.method().
Returning a promise from each of your functions.
The whole thing actually works better with a little renaming/refactoring to start with a connect() function rather than get().
var jwt = require('jwt-simple');
var mysql = require('mysql');
var async = require('async');
var Promise = require('bluebird');
var connection = mysql.createConnection({
host: 'localhost',
port: 3306,
database: 'abc',
user: 'root',
password: ''
});
//Promisify `connection`.
//Lucky you, Bluebird has a `.promisifyAll()` method.
Promise.promisifyAll(connection);
//Now, `auth` will be something like this :
var auth = {
login: function (req, res) {
var username = req.body.username || '';
var password = req.body.password || '';
//Let's assume you want to build an object containing various user details
var authObj = {
'userName': userName,
'email': null, //to be set later
'name': null //to be set later
};
function connect() {
return connection.connectAsync().catch(function(err) {
throw 'Error connecting: ' + err.stack;
});
}
function abc1() {
return connection.queryAsync("SELECT count(id) as count from abc where name=? AND email=?", [username, password]).then(function (rows) {
if (rows[0].count != 1) {
throw new Error('Invalid credentials');
}
});
}
function xyz() {
return connection.queryAsync("SELECT email from abc where name=? AND email=?", [username, password]).then(function(rows) {
return rows[0].email;
});
}
function pqr() {
return connection.queryAsync("SELECT name from abc where name=? AND email=?", [username, password]).then(function(rows) {
return rows[0].name;
});
}
return connect()
.then(abc1)//check credentials
.then(xyz)//get email
.then(function (email) {
authObj.email = email;
return pqr();//get name
})
.then(function (name) {
authObj.name = name;
return authObj;//make authObj available to auth.login()'s caller.
})
.catch(function (err) {
// handle any error resulting from any of the above calls.
console.log(err);
throw err;//make the error available to auth.login()'s caller.
});
}
}
As you will see, err doesn't feature in the code until the bottom of auth.login(). It is the nature of promisified nodebacks that errors propagate down the promise chain's error path, and don't need to be handled mid-chain unless you need to do something like mid-chain error recovery.
Whereas this is good for learning how to construct a promise chain, in practice you appear already to know name and email at the outset, and you would probably choose to login and obtain other user details in one hit with suitable SQL.
Related
Good day, I recently had help learning how to make things wait using callbacks, however now it's almost as if I hit a limit on how many can be used, but I can't seem to find information on this?
If I ran this code without tryToCreateAccount having a callback, it will connect, check and work as intended. As soon as I make tryToCreateAccount have a callback param, it appears to enter Connect.Connect (only sometimes) but then never query's.
Backend:
const mysql = require('mysql');
const connection = mysql.createConnection({
host: 'host',
user: 'user',
password: 'pass',
database: 'db'
});
export function tryToCreateAccount(login, password, passwordConfirm, callback)
{
checkAccountNameAvailable(login, connection, function(err, accountNameAvailable)
{
callback(err, accountNameAvailable);
});
}
function checkAccountNameAvailable(login, connection, callback)
{
var accountNameAvailable = true;
console.log("Checking account name", login);
connection.connect(function (err)
{
console.log("Checking Connect Method");
if(err) callback(err);
connection.query("SELECT login FROM accounts WHERE login = ?", login, function (err, result)
{
if (err) callback(err);
if(result.length > 0) accountNameAvailable = false;
console.log("returning ", accountNameAvailable);
callback(null, accountNameAvailable);
connection.end();
});
});
}
Front End:
tryToCreateAccount($w('#input1').value, $w('#input2').value, $w('#input3').value, function (err, callback)
{
if(callback)
{
console.log("Was True");
}
else
{
console.log("Was False");
}
});
UPDATED CODE:
Backend:
const mysql = require('mysql');
const pool = mysql.createPool(
{
connectionLimit : 10,
host : 'host',
user : 'user',
password : 'pass',
database : 'db'
});
export function tryToCreateAccount(login, password, passwordConfirm, callback)
{
checkAccountNameAvailable(login, pool, function(err, accountNameAvailable)
{
if(err)
{
console.log(err);
callback(err, null);
}
callback(err, accountNameAvailable);
});
}
function checkAccountNameAvailable(login, pool, callback)
{
var accountNameAvailable = true;
console.log("Checking account name", login);
pool.getConnection(function (err, connection)
{
console.log("Made a connection.");
if(err)
{
console.log(err);
callback(err, null);
connection.destroy();
}
connection.query("SELECT login FROM accounts WHERE login = ?", login, function (err, result)
{
console.log("Checking Query Method");
if (err)
{
console.log(err);
callback(err, null);
}
if(result.length > 0) accountNameAvailable = false;
console.log("returning ", accountNameAvailable);
callback(null, accountNameAvailable);
connection.destroy();
});
});
}
Frontend is the same
Output:
Checking account name testaccount
I am new in nodejs. I am creating a basic API to get record by id. Everything is working fine. It is returning user data from database. But when i use password variable from response in same function it give me empty value whereas i am getting value in response. I think this is async issue but i dont know how to fix it.
This is API code
var express = require('express');
var db = require('../db/database');
var bcrypt = require('bcrypt');
const router = express.Router();
router.get("/:userId", (req, res, next) => {
let uid = req.params.userId;
db.query(`SELECT * FROM users WHERE u_id = ${uid}`, (err, data)=> {
if(!err) {
if(data && data.length > 0) {
var message = '';
if(data.u_password){
//var pass = data.u_password;
if(bcrypt.compare('123456', data.u_password)) {
// Passwords match
message = 'Passwords match';
} else {
// Passwords don't match
message = 'Passwords dont match';
}
}
res.status(200).json({
message:message,
});
} else {
res.status(200).json({
message:"User Not found."
});
}
}
});
});
database.js
var mysql = require('mysql');
const pool = mysql.createPool({
connectionLimit : 10,
host: 'localhost',
user: 'root',
password: '',
database: 'lost_and_found',
debug : false
});
function executeQuery(sql, callback) {
pool.getConnection((err,connection) => {
if(err) {
return callback(err, null);
} else {
if(connection) {
connection.query(sql, function (error, results, fields) {
connection.release();
if (error) {
return callback(error, null);
}
return callback(null, results);
});
}
}
});
}
function query(sql, callback) {
executeQuery(sql,function(err, data) {
if(err) {
return callback(err);
}
callback(null, data);
});
}
module.exports = {
query: query
}
Response
{"message":""}
Please change the bcrypt.compare code to following code. It is a callback function:
bcrypt.compare('123456', data.u_password, function(err, result) {
if (err) {
// Passwords don't match
message = 'Passwords dont match';
} else {
// Passwords match
message = 'Passwords match';
}
res.status(200).json({
message:message,
});
})
EDIT 1: Please update the method to following logic:
db.query(`SELECT * FROM users WHERE u_id = ${uid}`, (err, data) => {
if (err) {
throw err;
}
if (data && data.length > 0) {
var message = '';
if (data.u_password) {
bcrypt.compare('123456', data.u_password, function (err, result) {
if (err) {
// Passwords don't match
message = 'Passwords dont match';
} else {
// Passwords match
message = 'Passwords match';
}
res.status(200).json({
message: message,
});
})
}
res.status(200).json({
message: "User Not found."
});
}
res.status(200).json({
message: "User Not found."
});
});
I'm trying to create a function in a file to return a promis, which I will call form another file. I'm trying to use the 'util.promisify' to wrap the function, but I'm getting an error. Here is the code and the error:
from my 'checkEmail.js':
const Profile = require('../../models/profile');
const util = require('util');
var exports = module.exports = {};
exports.findEmail = util.promisify(checkEmail());
function checkEmail (email) {
Profile.findOne({ 'emails': { $elemMatch: { email_address: email } } }, (err, userEmail) => {
let conclusion = false;
if (err) {
console.log('Error in looking up an existing email');
} else {
if (userEmail) {
console.log('We found an existing owner for email: ' + email);
conclusion = true;
}
}
return conclusion;
})
}
Calling it on 'profile.js':
router.route('/addemail/:id')
// ADD EMAILS
.put(function (req, res) {
Profile.findOne({ 'owner_id': req.params.id }, function (err, profile) {
if (err)
res.send(err);
EmailCheck.findEmail(req.body.email_address).then((data)=>{
console.log('The answer is: ', data);
});
profile.emails.push({
email_type: req.body.email_type,
email_address: req.body.email_address
})
profile.save(function (err) {
if (err)
res.send(err);
res.json(profile);
});
});
});
The error I'm getting is:
Config for: http://localhost:3000
internal/util.js:272
throw new ERR_INVALID_ARG_TYPE('original', 'Function', original);
Any help would be appreciated.
In order to promisify the function that you pass to util.promisify must:
Take a function following the common error-first callback style, i.e.
taking a (err, value) => callback as the last argument, and returns a version that returns promise
So you can either promisify Profile.findOne, or pass a callback as the last argument to checkEmail
function checkEmail (email, callback) {
Profile.findOne({ 'emails': { $elemMatch: { email_address: email } } }, (err, userEmail) => {
let conclusion = false;
if (err)
return callback(new Error('Error in looking up an existing email'));
if (userEmail) {
console.log('We found an existing owner for email: ' + email);
conclusion = true;
}
return callback(null, conclusion);
})
}
And then you should call it like this:
exports.findEmail = util.promisify(checkEmail);
Otherwise you're passing to .promisify the returned value of checkEmail which is not a function following the style commented above.
You have typo, use util.promisify(checkEmail) instead, parentheses are redundant
I'm still very new to Node.js, and i'm trying to understand how callbacks work.
So, here is my problem :
I should've put more code :
POST :
app.post('/register', function(req, res) {
//get data from the request
var data = {
username: req.body.username,
email: req.body.email,
password: req.body.password
};
function fetchID(callback) {
connection.query('SELECT id_user FROM USERS WHERE username = ?', data.username, function(err, rows) {
if (err) {
callback(err, null);
} else
callback(null, rows[0].id_user);
});
}
var user_id;
fetchID(function(err, content) {
if (err) {
console.log(err);
return next("Mysql error, check your query");
} else {
user_id = content;
console.log(user_id); //undefined
}
});
console.log(user_id); //undefined
var payload = {
iss: req.hostname,
sub: user_id
}
console.log(payload.sub); //correct id
})
GET :
app.get('/todos', function(req, res) {
if (!req.headers.authorization) {
return res.status(401).send({
message: 'You are not authorized !'
});
}
var token = req.headers.authorization.split(' ')[1];
var payload = jwt.decode(token, "shhh..");
//additional level of security
console.log('sub id is : ' + payload.sub); //undefined
if (!payload.sub) {
return res.status(401).send({
message: 'Authentication failed !'
});
}
})
I commented each console.log to be more clear. I need to get the correct id when i check for if (!payload.sub) in app.get()
Your two functions should be something like -
function fetchID(data, callback) {
connection.query('SELECT id_user FROM USERS WHERE username = ?', data.username, function(err, rows) {
if (err) {
callback(err, null);
} else
callback(null, rows[0].id_user);
});
}
and then
var user_id;
fetchID(data, function(err, content) {
if (err) {
console.log(err);
// Do something with your error...
} else {
user_id = content;
}
});
Here in the callback function, the returned variable content will hold the value for user_id.
EDIT
I have not solved the exact problem as you had described above.
But in following example, I have shown that, the callback mechanism is working -
First (Table creation and insert some dummy data)-
use test;
create table users (id int(11) primary key,username varchar(100));
insert into users values(1, "John");
insert into users values(2, "Sham");
Now I have made your post method as get and tested in browser.
Following is the full class tested in my localhost -
var application_root = __dirname,
express = require("express"),
mysql = require('mysql');
var app = express();
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'admin',
database: "test"
});
app.get('/getuser', function(req, res) {
//get data from the request
var data = {
username: req.query.username
};
function fetchID(data, callback) {
connection.query('SELECT id FROM users WHERE username = ?',
data.username, function(err, rows) {
if (err) {
callback(err, null);
} else
callback(null, rows[0].id);
});
}
var user_id;
fetchID(data, function(err, content) {
if (err) {
console.log(err);
res.send(err);
// Do something with your error...
} else {
user_id = content;
console.log(user_id);
res.send("user id is -" + user_id);
}
});
})
app.listen(1212);
Now these requests will produce this output -
http://127.0.0.1:1212/getuser?username=john => user id is -1 and
http://127.0.0.1:1212/getuser?username=sham => user id is -2
Hope this code example will help you to understand the callback in node.js.
Thanks
I'm using nodeJs express 3 framework with postgreSQL, I'm using the script below to look for a username in DB and populate a variable so I can pass it to my view.
Here is my script :
app.js
var app = express();
app.use(express.bodyParser());
......
function fncCheckUsernameAvailability(vstrUsername){
var pg = require("pg");
var client = new pg.Client({user: 'xxx', password: 'xxxx', database: 'xxx', host: 'example.com'});
var response = "";
client.connect(function(err) {
if(err) {
return console.error('could not connect to postgres', err);
}
client.query("SELECT username FROM users WHERE username ='"+vstrUsername+"'", function(err, result) {
if(err) {
return console.error('error running query', err);
}
if(result.rows[0] == undefined){
//console.log("Username available");
response = "Username available";//Populating The variable here
}else{
//console.log("Username already taken");
response = "Username already taken";//Populating The variable here
}
client.end();
});
});
return response;
}
app.post("/Signup", function(req, res){
var username = req.body.username;
var Response = fncCheckUsernameAvailability(username);
console.log(Response);
}
The response variable is allways "undefined", so how can I make that script waiting until the DB checking is done to populate the "response" variable?
You cannot place return values into asynchronous functions. You would instead need to use a callback, and this is what your code might look like:
function fncCheckUsernameAvailability(vstrUsername, callback) {
client.connect(function(err) {
if (err) {
callback(err, null);
return;
}
client.query("SELECT username FROM users WHERE username ='" + vstrUsername + "'", function (err, result) {
client.end();
if (err) {
callback(err, null);
return;
}
if (result.rows[0] == undefined) callback(null, 'Username available.');
else callback(null, 'Username taken.');
});
});
};
You would use the function like this:
app.post("/Signup", function(req, res) {
var username = req.body.username;
fncCheckUsernameAvailability(username, function(err, result) {
console.log(result);
});
});