I have strung together a promise to complete three actions synchronously. First, inserting into the db and resolving the id of that insert. Second, editing my json object to contain that last inserted id from the db. And third, sending a post request using npm requests. This is all wrapped in an express endpoint.
However, the requests call doesnt seem to be posting to my API. I have checked, removed the promises dependencies (which is needed to get the last inserted id from the db), and successfully posted the data using the exact same request structure. This leads me to beleive that
there is something wrong with my promise. Can anybody help?
function db() {
return new Promise(function(resolve, reject) {
db.run(`INSERT INTO scan_requests(name, date) VALUES(?,?);`, [req.body.name,req.body.date], function(err) {
if (err) {
console.log(err)
}
let q = this.lastID
resolve(q)
})
})
}
db()
.then(function(q) {
let data = {
url: 'https://api/key/',
body: {
name: req.body.name,
scan_callback: `http://localhost:80/${q}`
},
json: true
}
return(data)
}).then(function(data) {
res.json(req.body)
request
.post(data)
.on('error', function(err) {
console.log(err)
})
.pipe(res)
})
To chain promises, the resolve callback (executed in then) needs to return another promise, so you can chain another then to the first promise.
Just like this:
function db() {
return new Promise(function (resolve, reject) {
const str = 'Message from first Promise'
resolve(str)
})
}
db()
.then(function (outputFromFirstPromise) {
return new Promise(function (resolve, reject) {
const somethingElse = ', and output from second promise'
const result = outputFromFirstPromise + somethingElse
resolve(result)
})
})
.then(function (outputFromSecondPromise) {
// do something with outputFromSecondPromise
})
In your case the promise in the middle is not needed at all though. Why would you use a promise, only to construct your object data if you have nothing async to handle? Just put everything in the callback of your first promise.:
db().then(function (q) {
let data = {
url: 'https://api/key/',
body: {
name: req.body.name,
scan_callback: `http://localhost:80/${q}`
},
json: true
}
res.json(req.body)
request
.post(data)
.on('error', function (err) {
console.log(err)
})
.pipe(res)
})
Related
I've written a web interface to allow users to query AWS Athena. It is using NodeJS Promises with Async and Await, but the error handling is not good. When a user enters an invalid SQL query (table not found), the response is always "{}". I've tried Athena-express and Athena-client. I then tried the Athena-client "toStream()" syntax.
var stream = client.execute('SELECT * from sometable limit 1').toStream()
stream.on('data', function(record) { console.log('record='+JSON.stringify(record)) })
stream.on('query_end', function(queryExecution) { console.log(queryExecution) })
stream.on('end', function() { console.log('end') })
stream.on('error', function(e) { console.error(e) })
And it returned an error. I thought great, let me encapsulate it in a promise. I've used:
new Promise((resolve, reject) => ...
require('stream/promises');
require('stream-promise');
Essentially, the moment I put it in a promise, the error I get back is always "{}". Does anyone know how you can get the actual Athena error returned using promises without it crashing the app?
let executeQuery = new Promise((resolve, reject) =>
{
let response = client.execute('SELECT * from sometable limit 1').toStream();
response.on('error', (err) => { reject(err); })
response.on('finish', function() { resolve(response); })
})
async function run()
{
try
{
let response = await executeQuery;
console.log('response='+JSON.stringify(response));
}
catch(e) { console.log('MY error='+JSON.stringify(e)) }
}
run();
It returns "My error={}", and I need it to return "Table sometable does not exist"
Found my issue. I can't JSON.stringify(e) I have to JSON.stringify(e.message)
const output = JSON.stringify(e.message);
That was annoying!
Here I am trying to retrieve objects and push them into the array. For some reason there is only one record being pushed into the file when it should contain more objects. Can you help me out with this or let me know where I am going wrong? Here is my code:
exports.createjson = (req, res, next) => {
try {
var myPromise = () => {
// ...
};
var callMyPromise = async () => {
const responsearray = [];
var result = await myPromise();
return new Promise((resolve, reject) => {
result.forEach(element => {
NewsModel.findOne({ _id: element.newsId }).exec(
async (err, result) => {
if (err) {
throw err;
}
reportsModel
.findOne({
$and: [
{ userId: req.query.userId },
{ newsId: element.newsId }
]
})
.exec((err, newsResult) => {
if (err) {
throw err;
}
// console.log(newsResult);
var response = {
newsId: element.newsId,
title: result.title,
collection: result.group,
belivibalityIndex: element.belivibalityIndex,
priorknowledge: element.priorknowledge,
readingTime: element.readingTime,
userId: element.userId,
comment: element.comment,
report: newsResult !== null ? newsResult.feedback : null
};
// #all object pushed and displayed in console
responsearray.push(response);
console.log(response);
console.log(responsearray.length);
// let data = JSON.stringify(responsearray);
// #here is the issue // fs.writeFileSync("abc.json", data, null, null, flag = 'a');
return responsearray;
});
}
);
});
});
};
callMyPromise().then(function(responsearray) {
res.json(responsearray);
});
} catch (error) {
next(error);
}
};
You're not quite using Promises properly. For example, you create a Promise object but never call the resolve/reject functions. In the forEach loop you are calling functions that use callbacks and when that work is done you can resolve the promise you're wrapping it in.
Also you're calling res.json and writing the file (though it's commented out) while you're in the forEach loop. That means res.json will get called multiple times, which is not allowed. You can only have one response from an http request.
I restructured the code so that it collects each promise in an array of Promises then waits for all of them to resolve. Only after all of the work is done, we can write the file and call res.json to complete the http request.
exports.createjson = async (req, res, next) => {
const responsearray = [];
var elements = await myPromise();
var promises = []; // collect a bunch of promises to wait on
elements.forEach(element => {
// one promise per element that resolves when response is on the array
var promise = new Promise(function(resolve, reject) {
NewsModel.findOne({ _id: element.newsId }).exec((err, result) => {
if (err) { return reject(err); }
reportsModel
.findOne({
$and: [{ userId: req.query.userId }, { newsId: element.newsId }]
})
.exec((err, newsResult) => {
if (err) { return reject(err); }
var response = { /* response body */ };
responsearray.push(response);
console.log(response);
console.log(responsearray.length);
// complete the promise now that the response is on the array
return resolve();
});
});
});
// collect each promise in an array so we can wait for them all
promises.push(promise);
});
// wait for all the work to complete
await Promise.all(promises).catch(err => next(err));
// write the responsearray to a file as json
let data = JSON.stringify(responsearray);
fs.writeFileSync("abc.json", data);
return res.json(responsearray);
};
I also removed the try/catch block since the Promise allows you to use .catch in a cleaner way. It simplifies the nesting which makes it easier to read.
The key takeaway here is the general structure:
// get your array to work with
var array = await someFunction()
var manyPromises = []
var manyResults = []
// for each thing in the array create a promise
array.forEach( thing => {
manyPromises.push( new Promise((resolve,reject) => {
doSomething(thing, (err, result) => {
if (err) return reject(err);
// store the results in the array and resolve the promise
manyResults.push(result)
return resolve();
});
});
});
// wait for all promises in manyPromises to complete
await Promise.all(manyPromises).catch(err => return next(err));
// now the many promises are done and manyResponses are ready
saveResponsesToFile(JSON.stringify(manyResponses))
return res.json(manyReponses)
My Codes below;
I've a then-catch block. My responseArray is a global variable. i got response from functionName function; but i can't use result out of then block. How can i use then response out of block?
My Codes below;
I've a then-catch block. My responseArray is a global variable. i got response from functionName function; but i can't use result out of then block. How can i use then response out of block?
module.exports = {
foo1: function(param){
return new Promise((resolve,reject) => {
var result = //some code here
resolve(result);
});
},
foo2: function(param){
return new Promise((resolve,reject) => {
this.foo1('abc').then(function(res){
let response = {
'item':'ok',
'result':res.some_field
};
console.log(response); // its ok here.
responseArray.push(response); //its ok here too
}).catch(err =>{
console.log(err);
reject(err);
});
console.log(responseArray); //nothing in array here
resolve(responseArray);
});
}
};
First thing to remember is that promises are asynchronous. Promises are doing exactly what they say, you are essentially signing a contract (promise) that you will get your data (or error) but not synchronously, but at some time in the future when the computations have finished.
In order to access your responseArray you will need to resolve your foo2 promise (inside of .then) and continue the promise chain by calling it, i.e.
module.exports = {
foo1: function(param){
return new Promise((resolve,reject) => {
var result = //some code here
resolve(result);
});
},
foo2: function(param){
return new Promise((resolve,reject) => {
this.foo1('abc').then(function(res){
let response = {
'item':'ok',
'result':res.some_field
};
console.log(response); // its ok here.
responseArray.push(response); //its ok here too
resolve(responseArray) // resolve the promise inside of .then
}).catch(err =>{
console.log(err);
reject(err);
});
});
}
};
foo2('someValue').then(response => {
console.log(response) // this will be your array
})
Also, as a side note, ensure you are not falling into the trap of the promise constructor anti-pattern. This is where you unnecessarily turn synchronous code into asynchronous code just for the sake of using "promises"
For example, a valid use of a promise would be to convert a callback, like so:
const getFile = filename => {
return new Promise((resolve, reject) => {
fs.readFile(filename, 'utf8', (err, data) => {
if (err) reject(err)
resolve(data)
})
})
}
whereas this is unnecessary:
const printData = data => {
return new Promise((resolve, reject) => {
resolve(console.log(data))
})
}
vs
const printData = data => {
console.log(data)
}
Read more here: What is the explicit promise construction antipattern and how do I avoid it?
I am having a problem retrieving data from database using sequelize js. I am new to NODEJS. I don't know if Promise and Promise.all are built in functions
So i install and require npm promise in my code too.
Below is my code.
var Promise = require('promise');
var user_profile = new Promise(function(resolve, reject) {
db.user_profile.findOne({
where: {
profile_id: new_profile_id
}
}).then(user => {
console.log('Summary Result User found.');
resolve(user);
});
});
var all_reports = new Promise(function(resolve, reject) {
db.report.all().then(reports => {
console.log('Summary Result Reports found.');
resolve(reports);
});
});
var report_details = new Promise(function(resolve, reject) {
db.report_detail.findAll({
where: {
profile_id: new_profile_id
}
}).then(report_details => {
console.log('Summary Result Report Details found');
resolve(report_details);
});
});
var all_promises = Promise.all([user_profile, all_reports, report_details]).then(function(data) {
console.log('**********COMPLETE RESULT****************');
console.log(data);
}).catch(err => {
console.log('**********ERROR RESULT****************');
console.log(err);
});
I want to get the data of all three queries. When i run them individually I get the data but when i run them in Promise.all I only get user_profile data and other two remain undefined
I have also tried nested these queries with .then but result is still same I only get one query data other two remain undefined
with then chainging
var results = [];
var new_profile_id = req.params.profile_id;
console.log(new_profile_id);
db.user_profile.findOne({
where: {
profile_id: new_profile_id
}
}).then(user => {
console.log('Summary Result User found.');
results.push(user.dataValues);
return user;
}).then(user => {
db.report.all().then(reports => {
console.log('Summary Result Reports found.');
results.push(reports.dataValues);
return reports
});
}).then(reports => {
db.report_detail.findAll({
where: {
profile_id: new_profile_id
}
}).then(report_details => {
console.log('Summary Result Report Details found');
results.push(report_details.dataValues);
console.log('**********COMPLETE RESULT****************');
console.log(results);
console.log('**********COMPLETE RESULT****************');
return report_details;
});
});
can someone please help me in this concept what i am doing wrong.
Thanks
The latest version of Node.js already supports Promise natively, so does Sequelize. This means no need to require promise separately.
The following code is based on yours.
const user_profile = db.user_profile.findOne({
where: {
profile_id: new_profile_id
}
});
const all_reports = db.report.all();
const report_details = db.report_detail.findAll({
where: {
profile_id: new_profile_id
}
});
Promise
.all([user_profile, all_reports, report_details])
.then(responses => {
console.log('**********COMPLETE RESULTS****************');
console.log(responses[0]); // user profile
console.log(responses[1]); // all reports
console.log(responses[2]); // report details
})
.catch(err => {
console.log('**********ERROR RESULT****************');
console.log(err);
});
Notice that there is no need to wrap Sequelize calls with Promise becasue Sequelize already returns promises. This way you only need to have one catch in the last Promise.all() which you were missing in all calls. What this means is that if any calls were to fail, a corresponding resolve would never be called. This, in turn, means that the last Promise.all() would also never be called. This is why it is good to handle all errors at the end once, unless there are some custom error handling requirements.
I'm trying to return from my node server with koa to my angular front end the result of an api call. Here's my controller which require a npm module which provides access to their api. Await should wait for the result and than return, am I wrong? I did something similar in a previous project but I was asking data from a db.
Why it is not working?
const color = require('colourlovers');
exports.getAllColors = async (ctx) => {
ctx.res.body = await color.get('/color/FFFFFF', { format: 'json' }, (err, data) => {
console.log(data);//<---here is logging the data
return data;
});
console.log(ctx.res.body);//<---here is undefined
ctx.status=200;
};
You can not await color.get because it uses callbacks instead of promises (well, you can await it, but it doesn't do what you'd expect). So to use await, you need to build the promise yourself:
ctx.res.body = await new Promise((resolve, reject) => {
color.get('/color/FFFFFF', { format: 'json' }, (err, data) => {
if(err) reject(err);
else resolve(data);
});
});
Now it'll wait for the promise to be resolved or rejected.