I have some routes
routes.js
var express = require("express");
var router = express.Router();
const { controllerMethod1, controllerMethod2 } = require("./controller");
router.get("/route1", controllerMethod1);
router.get("/route2", controllerMethod2);
module.exports = router;
if i use promise variable as global,
its used by all method in controller.js.
should i use global or local variable for promise ?
controller.js
const {
serviceMethod1,
serviceMethod2,
serviceMethod1ByDate,
} = require("./services");
let promise; //global promise variable
const controllerMethod1 = (req, res) => {
//let promise; local promise variable
//This is for Callback
if (req.query.date) {
serviceMethod1ByDate(req.query.date, (err, result) => {
if (err) {
res.status(500).json({
status: "error",
message: "error using callback",
});
}
if (result) {
res.status(200).json({
status: "success",
message: "success using callback",
});
}
});
} else {
serviceMethod1((err, result) => {
if (err) {
res.status(500).json({
status: "error",
message: "error using callback",
});
}
if (result) {
res.status(200).json({
status: "success",
message: "success using callback",
});
}
});
}
// This is for Promise
promise = req.query.date
? serviceMethod1ByDate(req.query.date)
: serviceMethod1();
Should i use way 1 or way 2 ?
if multiple users request one or more routes at the same time,can handleResponse method work correctly?
Way 1 for promise
promise
.then((results) => {
return res.json({
status: "success with promise variable",
data: results,
});
})
.catch((error) => {
return res.status(500).json({
status: "error with promise variable",
message: "there is no person details",
});
});
Way 2 for Promise
handleResponse(promise, res);
//this method is working for all routes when i use promise
const handleResponse = (results, response) => {
results
.then((result) => {
return response.json({
status: "success with promise variable in handleResponse",
data: result,
});
})
.catch((error) => {
return response.status(500).json({
status: "error with promise variable handleResponse",
message: "Internal Server Error",
});
});
};
controller.js
const controllerMethod2 = (req, res) => {
//------------------ Using Callback Method -------------
serviceMethod2((err, result) => {
if (err) {
res.status(500).json({
status: "error",
message: "error using callback",
});
}
if (result) {
res.status(200).json({
status: "success",
message: "success using callback",
});
}
});
//------------------ Using Promise Method -------------
//local variable
let promise;
promise = serviceMethod2();
//Way 1 for Promise
promise
.then((result) => {
//...
})
.catch((err) => {
//...
});
//Way 2 for Promise
handleResponse(promise, res);
};
module.exports = { controllerMethod1, controllerMethod2 };
service.js
const pool = require("../../../config/database");
//-----------------------Using Callback Mehthod----------------
const serviceMethod1 = async (CallBack) => {
let query = "select * from databse";
await pool.query(query, [], (error, results, fields) => {
if (error) {
return CallBack(error);
}
return CallBack(null, results);
});
};
const serviceMethod1ByDate = async (date) => {
let query = "select * from databse where date ?";
return await new Promise((resolve, reject) => {
pool.query(query, [date], (error, results, fields) => {
if (error) {
return CallBack(error);
}
return CallBack(null, results);
});
});
};
const serviceMethod2 = async (Callback) => {
let query = "select * from database";
await pool.query(query, [], (error, results, fields) => {
if (error) {
return CallBack(error);
}
return CallBack(null, results);
});
};
//-----------------------Using Promise Method----------------
const serviceMethod1 = async () => {
let query = "select * from databse";
return await new Promise((resolve, reject) => {
pool.query(query, [], (error, results, fields) => {
if (results) {
resolve(results);
} else {
reject(error);
}
});
});
};
const serviceMethod1ByDate = async (date) => {
let query = "select * from databse where date ?";
return await new Promise((resolve, reject) => {
pool.query(query, [date], (error, results, fields) => {
if (results) {
resolve(results);
} else {
reject(error);
}
});
});
};
const serviceMethod2 = async () => {
let query = "select * from database";
return await new Promise((resolve, reject) => {
pool.query(query, [], (error, results, fields) => {
if (results) {
resolve(results);
} else {
reject(error);
}
});
});
};
module.exports = {
serviceMethod1,
serviceMethod1ByDate,
serviceMethod2,
};
if i use promise variable as global, its used by all method in controller.js. should i use global or local variable for promise ?
You should use local variable for this type of operation as global variable are generally used to define constants or methods. They cannot be used as temporary values because it's value can be changed anytime and that'll result in conflict with other functionalities and so must be avoided.
Should i use way 1 or way 2 ? if multiple users request one or more routes at the same time,can handleResponse method work correctly?
Way 2 is more efficient that Way 1 because if you use way 1 then you will have to do it for every method in the controller. Way 2 is like a common method where you can format your response and most of the developers use it.
It doesn't make any difference whether you use callbacks or promises but just a clean way to do things.
Instead of using this:
const serviceMethod1 = async () => {
let query = "select * from databse";
return await new Promise((resolve, reject) => {
pool.query(query, [], (error, results, fields) => {
if (results) {
resolve(results);
} else {
reject(error);
}
});
});
};
Use this:
// Remove the async await from here and handle the response/error where the below method is called by putting it in try catch block.
const serviceMethod1 = () => {
let query = "select * from databse";
return new Promise((resolve, reject) => {
pool.query(query, [], (error, results, fields) => {
if (results) {
resolve(results);
} else {
reject(error);
}
});
});
};
// otherFile.js
someMethod = async () => {
try {
const result = await serviceMethod1();
// handle the response
} catch {
// handle the error
}
}
Related
I have already a function written with bluebird promises and I would like to rewrite it with async and await. When I have made the changes I have found out that earlier with promises the reject statement always transfers the control to called function catch block though if the catch block is already there in the file from where we are rejecting. How to handle this situation properly with async and await?. (Added comments to the code to explain the issue)
With Promise:
const callingFunc = (req, res) => {
return new Promise((resolve, reject) => {
// execute request which returns promise
functionCall()
.then((response) => {
let error;
try {
xml2js(response.body, { explicitArray: false }, (err, result) => {
if (err) {
return reject(err); /* throws the correct error to catch block of the file from where callingFunc is called*/
}
if (!_.isEmpty(result.Response.errorCode)) {
return reject(result.Response); /* throws the correct error to the catch block of the file from where callingFunc is called*/
}
return resolve(result);
});
} catch (e) {
error = new Error('xml2js conversion error');
reject(error);
}
})
.catch((error) => {
const Error = new Error('Internal Server Error');
reject(Error);
});
});
};
With async and await:
const callingFunc = (req, res) => {
try {
const response = await functionCall();
let error;
try {
xml2js(response.body, { explicitArray: false }, (err, result) => {
if (err) {
throw (err); /* throws the error to the below catch block and returning xml2js conversion error and changing behaviour*/
}
if (!_.isEmpty(result.Response.errorCode)) {
throw result.Response; /* throws the error to the below catch block and returning xml2js conversion error and changing behaviour*/
}
return result;
});
} catch (e) {
error = new Error('xml2js conversion error');
throw error;
}
} catch(error) {
const Error = new Error('Internal Server Error');
throw Error;
}
};
If functionCall returns a promise, then this code is inappropriate...
return new Promise((resolve, reject) => {
// execute request which returns promise
functionCall()
.then((response) => {
If xml2js is async using callbacks, then it is appropriate to wrap it in a promise...
// return a promise that resolves with the result of xml2js
async function xml2js_promise(body) {
return new Promise((resolve, reject) => {
xml2js(body, { explicitArray: false }, (err, result) => {
if (err) reject(err);
else if (!_.isEmpty(result.Response.errorCode)) reject(result.Response);
else resolve(result);
});
});
}
Now we can await these. There's no need to nest the try's. (And you only need the try if you're going to do something on the catch).
async callingFunction = (req, res) => {
try {
const response = await functionCall();
} catch (error) {
// do something with this error
}
try {
const result = await xml2js_promise(response.body)
} catch(error) {
// do something with this error
}
return result;
}
I want to update ans object inside the fetchAll() functions and then send it back after successful updation. But the response I get is '[]'.
var ans = []
Country.fetchAll(newdate,(err, data) => {
if (err)
res.status(500).send({
message:
err.message || "Some error occurred while retrieving data."
});
else ans.push(data);
});
State.fetchAll(newdate2,(err, data) => {
if (err)
res.status(500).send({
message:
err.message || "Some error occurred while retrieving data."
});
else ans.push(data);
});
res.send({ status: 201, data: ans });
How do I update the ans array inside the functions?
You can convert callback to Promise and using async/await to control the flow. async/await is supported in Node.js 7.6
const getCountry = (date) =>
new Promise((resolve, reject) => {
Country.fetchAll(date, (err, data) => {
if (err) {
reject(
new Error(err.message || "Some error occurred while retrieving data.")
);
return;
}
resolve(data);
});
});
const getState = (date) =>
new Promise((resolve, reject) => {
State.fetchAll(date, (err, data) => {
if (err) {
reject(
new Error(err.message || "Some error occurred while retrieving data.")
);
return;
}
resolve(data);
});
});
const foo = async (res) => {
try {
const [country, state] = await Promise.all([
getCountry(newdate),
getState(newdate2),
]);
const ans = [country, state];
res.send({ status: 201, data: ans });
} catch (err) {
res.status(500).send({ message: err.message });
}
};
Node.js v8 added util function to promisify the callback, the code can be simplified to
const util = require('util');
const foo = async (res) => {
try {
const getCountry = util.promisify(Country.fetchAll);
const getState = util.promisify(State.fetchAll);
const [country, state] = await Promise.all([
getCountry(newdate),
getState(newdate2),
]);
const ans = [country, state];
res.send({ status: 201, data: ans });
} catch (err) {
res.status(500).send({ message: err.message || "Some error occurred while retrieving data." });
}
};
How to reject a promise, if mysql query returns no records?
I have tried something like results.length === 0 but it doesn't work. My promise is resolved with an empty array of records. How can i reject a promise, if sql query returns nothing(record is not found in the database)?
My function which should handle the request:
function Sres_login(pool, res, params) {
const {ServerResponse} = require("./ServerResponse");
const contentCreator = Sres_promise(pool, params);
ServerResponse(contentCreator, res);
}
function Sres_promise(pool, {username, password}) {
return new Promise((resolve, reject) => {
const {query} = require("mysql");
pool.query(`SELECT * FROM accounts WHERE Login = '${username}' AND Password = '${password}'`, (error, results) => {
if (error || results.length === 0) {
reject("Niepoprawny login lub haslo");
}
else {
console.log(results);
resolve(results);
}
});
});
}
module.exports = {
Sres_login,
}
Server response:
function ServerResponse(contentCreator, res){
let content = {error: null, message: null};
return contentCreator
.then((message) =>
{
content.error = false;
content.message = message;
})
.catch((error) => {
content.error = true;
content.message = error;
})
.finally(() => {
res.send(content);
})
}
module.exports={
ServerResponse,
}
Edit:
Please help me, I need to implement a function in a separate module file and in the route where the render has to call this function receiving the query data:
function getSobre() {
return new Promise((resolve, reject) => {
db.query(`SELECT * FROM sobre ORDER BY cod DESC LIMIT 1`, (err, results) => {
if (err) {
return reject(err);
} else {
return resolve(results);
}
});
});
}
const data = {
title: getSobre().then(data => {
/*
* HERE How do I return this "data" to the "title:" ?????????????
*/
}),
name: 'Fabio',
profession: 'Analista'
}
module.exports = data;
db.query is a Js callback . Which will wait for the result , then return anything.
So data will always be empty since it is getting returned much before db.query getting full resolved
You should wrap this in a native promise, and then resolve the promise :
function getTabela{
return new Promise(function(resolve, reject) {
// The Promise constructor should catch any errors thrown on
// this tick. Alternately, try/catch and reject(err) on catch.
let sql = "SELECT * FROM sobre ORDER BY cod DESC LIMIT 1";
var data = {};
db.query(sql, (err, results, fields) => {
if (results.length > 0) {
resolve(fields)
} else {
console.log('Erro: ' + err);
}
});
});
}
getTabela().then(function(rows) {
// now you have your rows, you can see if there are <20 of them
}).catch((err) => setImmediate(() => { throw err; }));
This way you should always have the data which is expected out of the query.
My backend is consist of Api and DB. When I want to get response from DB I have had delayed output by 1 query.
API (I think api is ok. Start read DB first)
app.post('/api/query', (req, res) => {
console.log(`\n Query input : ${JSON.stringify(req.body)}`);
let queryInput = (Object.values(req.body).join(' '));
if(!dbApi.checkArray(queryInput)){ //If array is not made from clear strings
res.json(dbApi.queryFromUser(queryInput));
}
else{
res.json(dbApi.queryOutput);
}
});
app.listen(dbConfig.server.port, () =>
console.log(`Server running on port ${dbConfig.server.port}`));
DB
queryOutput = [];
const receivingQuery =(queryInput) => {
db.query(queryInput, (err, result) =>{
if(err) throw err+' : '+queryInput;
queryOutput = result;
console.log("\nQuery output "+ JSON.stringify(queryOutput)); //Output (result) is ok
});
return queryOutput //Here is Output from previous query (sends to API)
}
module.exports = {
queryOutput: queryOutput,
queryFromUser: receivingQuery,
}
I tryied callback method and I rewrite it couple of times. But I dont have enough skill to solve it.
If You want to return result of query so simply do following things:
add query method to db module:
function query(sql, args = []) {
return new Promise(function(resolve, reject) {
db.query(sql, args, (err, result) => {
if (err) return reject(err);
resolve(result);
});
});
}
// extra feature, getting user by id
async function getUserById(id) {
const result = await query('SELECT * FROM users WHER id = ? LIMIT 1', [id]);
if (Array.isArray(result) && result[0]) return result[0];
return null;
}
module.exports = {
query,
getUserById, // export user by id
queryOutput,
queryFromUser: receivingQuery,
}
use it (with async and await):
app.post('/api/query', async (req, res) => {
try {
console.log('Query input:', req.body);
const queryInput = Object.values(req.body).join(' ');
const result = await dbApi.query(queryInput);
res.json(result);
}
catch (error) {
console.error(error);
res.status(500).json({message: 'Please try again soon'});
}
});
app.get('/api/users/:id', async (req, res) => {
try {
const user = await dbApi.getUserById(req.params.id);
if (!user) return res.status(404).json({message: 'User not found'});
res.status(200).json(user);
}
catch (error) {
console.error(error);
res.status(500).json({message: 'Please try again soon'});
}
});
app.listen(dbConfig.server.port, () =>
console.log('Server running on port', dbConfig.server.port));