Using promises for db and server - javascript

Im still learning js, but im trying to write a basic server in nodejs.
The server is supposed to take a query and then return a JSON from a db.
Im trying to use promises but can get my head around this.
My server returns an empty reply.
So what am i doing wrong?
My server file so far (simplified):
http.createServer(function (request, response) {
if (request.method === "GET") {
...
var dbRes = dbFunc.getFromDB(query);
response.statusCode = 200;
response.setHeader('Content-Type', 'application/json');
response.end(JSON.stringify(dbRes));
}
}).listen(port);
My db file so far (simplified):
exports.readHandeler = function (query) {
var promise = new Promise(function(resolve, reject) {
db.collection('data').find(query).toArray(function(err, res) {
if (err) {
throw err;
reject(-1);
}
resolve(res);
}
});
promise.then(function(result) {
return result;
}, function(err) {
return -1;
});
}

My server returns an empty reply. So what am i doing wrong?
Your dbRes will be undefined since you're expecting a response from async promise execution. You need to send response only after promise resolves.
Making this change to your code
http.createServer(function (request, response) {
if (request.method === "GET") {
...
dbFunc.getFromDB(query).then((dbRes) => {
response.statusCode = 200;
response.setHeader('Content-Type', 'application/json');
response.end(JSON.stringify(dbRes));
}).catch((err) => {
console.log('err', err.stack);
});
}
}).listen(port);
Also, you need to return Promise in db execution part.
exports.readHandeler = function (query) {
return new Promise(function (resolve, reject) {
db.collection('data').find(query).toArray(function (err, result) {
if (err) {
return reject(err); // or -1 based on your need
}
return resolve(result);
});
});
};

Related

UnhandledPromiseRejectionWarning despite multiple Error checks

I recently have been developing a web app with NODEJS. I have a db model that takes care of all crud operations. Sample DB model
getDeviceList: function () {
return new Promise(function (resolve, reject) {
var sql = "SELECT * FROM `devices`";
db.query(sql, function (err, result) {
if (err) {
console.log(`FAILED: ${err}`);
reject(err);
} else resolve(result);
});
});
}
And I access this function in DB module like
router.get("/inventory/devices", checkAuth, function (req, res, next) {
return new Promise(function (resolve, reject) {
db.getDeviceList().then(function (result) {
resolve(res.status(200).json(result));
}).catch(function (err) {
console.log(`FAILED: ${err}`);
reject(res.status(200).json(err));
});
});
});
Sometimes when I close the DataBase; I get UnhandledPromiseRejectionWarning but In my eyes I am handling all the promises. What is the best way of handling promises and is my method of retrun promise correct?
My DB connection block is in app.js
var connection = db.connectDB().then(function (connect) {}).catch(function (err) {
console.log(`FAILED: ${err}`);
});
and my connectDB() is
function () {
return new Promise(function (resolve, reject) {
db = mysql.createPool({
host: "localhost",
port: 3306,
user: "migration",
password: "iub5015",
database: "migration"
});
db.getConnection(function (err) {
if (err) {
console.log(`FAILED: ${err}`);
reject(err);
} else {
console.log("Connected");
resolve(db);
}
});
});
}
The last statement in your catch block,
reject(res.status(200).json(err));
means that the returned promise is in rejected state. ie the Promise returned by router.get("/inventory/devices", checkAuth, function (req, res, next) is in rejected state and you have missed to catch that. (or express does not catch that as it seems in your case)
This is why you are getting this UnhandledPromiseRejectionWarning.
What is the best way of handling promises and is my method of retrun
promise correct?
Well, in my experience it depends. In some scenarios you may want to propagate error by rejecting Promise, or in some case you may just want to handle it some way and return something as resolved value. In your case you may have to look into express docs to figure out how you need to implement promises within your middleware.
router.get("/inventory/devices", checkAuth, function (req, res, next) {
return new Promise(function (resolve, reject) {
db.getDeviceList().then(function (result) {
resolve(res.status(200).json(result));
}).catch(function (err) {
console.log(`FAILED: ${err}`);
// This will not give UnhandledPromiseRejectionWarning
resolve(res.status(500).json(err));
});
});
});
router.get("/inventory/devices", checkAuth, function (req, res, next) {
new Promise(function (resolve, reject) {
db.getDeviceList().then(function (result) {
resolve(result);
}).catch(function (err) {
console.log(`FAILED: ${err}`);
reject(err);
});
}).then(r => {
res.status(200).json(r)
}).catch(er => {
res.status(400).json(er)
})
});

return response in a function in express app

As we know, we must return the response in the express app to avoid "Cannot set headers after they are sent to the client" error.
However, In below code, I'm trying to return the response but It's returning to our router and causes mentioned error. how I can directly return the response in function?
router.post("/admins", async function (req, res) {
var newAdminObj = await newAdminObjectDecorator(req.body, res);
var newAdmin = new Admins(newAdminObj)
newAdmin.save(function (err, saveresult) {
if (err) {
return res.status(500).send();
}
else {
return res.status(200).send();
}
});
});
// the function
var newAdminObjectDecorator = async function (entery, res) {
// doing some kinds of stuff in here
// if has errors return response with error code
if (err) {
// app continues after returning the error header response
return res.status(500).send();
}
else {
return result;
}
}
Never run a response operation other than the controller's functions. Let the other function return the answer and decide according to the answer.
router.post("/admins", async function (req, res) {
var newAdminObj = await newAdminObjectDecorator(req.body);
if (newAdminObj instanceof Error) {
return res.status(500).send()
}
var newAdmin = new Admins(newAdminObj)
newAdmin.save(function (err, saveresult) {
if (err) {
return res.status(500).send();
}
else {
return res.status(200).send();
}
});
});
// the function
var newAdminObjectDecorator = async function (entery) {
// doing some kinds of stuff in here
// if has errors return response with error code
if (err) {
// app continues after returning the error header response
return err;
}
else {
return result;
}
}

Javascript, error when return on a main function

I have my function who call the DB to do something :
function callQuery(query) {
db.query(query, (err, res) => {
if (err) {
// Error DB connecion
console.log(err.stack)
} else {
// Send back the results
return(res.rows[0])
}
})
}
My problem is when I call this function by :
const idUser = callQuery("INSERT INTO blablabla RETURNING *")
My data is successfully added in the DB, but idUser came null. It should be res.rows[0]
I am using this tutorial (who instead of setting a variable, call console.log) : https://node-postgres.com/features/connecting
Thank you in advance
I think this is something due to asynchronous
let promisess = new Promise(function(resolve, reject) {
function callQuery(query) {
db.query(query, (err, res) => {
if (err) {
// Error DB connecion
console.log(err.stack)
} else {
// Send back the results
resolve(res.rows[0])
}
})
}
});
promisess.then((res)=> {
your data in res
});

Node.js: Async fs.writeFile queue is creating race condition?

I am trying to use async with node.js to handle multiple incoming POST requests to edit a JSON file. No matter how I refactor it, it will always make one of the edits and not the other. I though that using async.queue would force the operations to handle sequentially? What am I doing wrong?
My code:
var editHandler = function(task, done) {
var req = task.req;
var res = task.res;
fs.stat( "./app//public/json/" + "data.json", function(err, stat) {
if(err == null) {
console.log('File exists');
} else if(err.code == 'ENOENT') {
console.log("Error");
} else {
console.log('Some other error: ', err.code);
}
});
console.log(req.params.id);
console.log(req.body);
fs.readFile( "./app//public/json/" + "data.json", 'utf8', function (err, data) {
data = JSON.parse( data );
data[req.params.id] = req.body.school;
//console.log( data );
fs.writeFile("./app//public/json/" + "data.json", JSON.stringify(data), function (err){
if(err) {
return console.log(err);
}
})
res.redirect('/');
});
};
//Make a queue for the services
var serviceQ = async.queue(editHandler, 20);
serviceQ.drain = function() {
console.log('all services have been processed');
}
app.post('/edit_school/:id', function(req, res) {
serviceQ.push({req: req, res: res })
})
Thanks in advance for any insights! I am really new to using node.js for anything other than npm/webpack.

Promise not working properly

I am trying to do a nested query with MySql, put the result inside a variable and send over http, but the program always run console.log("test 2:"+rpsData); before the query finish. I already tried this, but still getting the same problem.
const express = require('express')
const app = express()
const mysql = require('mysql');
const Connection = require('mysql/lib/Connection');
const Promise = require('bluebird');
Promise.promisifyAll([
Connection
]);
const connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'root123',
database : 'mygallery'
});
app.get('/posts', function(request, response) {
var rpsData;
connection.connectAsync()
.then(function() {
connection.query('SELECT * FROM post WHERE approved = 1', function(err, rows, fields) {
if (err) throw err;
rpsData = rows;
for (var i in rows) {
connection.query('SELECT * FROM image WHERE postCode = ?', [rpsData[i].postCode], function(err, rows, fields) {
if (err) throw err;
rpsData[i].image = rows;
console.log("test 1:"+rpsData);
});
}
});
})
.then(function() {
response.send(rpsData);
console.log("test 2:"+rpsData);
})
.catch(function(error) {
console.error('Connection error.', error);
});
});
What's happening here is you're not tying all of the pieces of async code to the promise chain. Once we convert it to do so this should work.
First lets wrap calls to connection.query to return a promise. We then have to return that generated promise to attach it to the outer promises chain.
If you don't return a promise, it won't know that it has to wait for your code to finish executing and will move forward with the next .then() statement on the outside promise (from connection.connectAsync);
You need to apply the same treatment to the inner query.
Sample code:
app.get('/posts', function(request, response) {
connection.connectAsync()
.then(function() {
return new Promise(function(resolve, reject) {
connection.query('SELECT * FROM post WHERE approved = 1', function(err, rows, fields) {
if (err) reject(err);
resolve(rows.reduce(function(accumulator, current) {
return accumulator.then(function(rpsData){
return new Promise(function(resolve, reject){
connection.query('SELECT * FROM image WHERE postCode = ?', [current.postCode], function(err, rows, fields) {
if (err) reject(err);
current.image = rows;
console.log("test 1:"+rpsData);
resolve(rpsData);
});
});
});
}, Promise.resolve(rows)));
});
});
})
.then(function(rpsData) {
response.send(rpsData);
console.log("test 2:"+rpsData);
})
.catch(function(error) {
console.error('Connection error.', error);
});
});
I'm queueing the internal promises using the technique I describe here

Categories

Resources