Not getting data after dependent api call using async problem node - javascript

I am calling API to fetch data on the basis of that data I am calling different APIs which is based on condition.
I have used a promise to maintain the async code as well but no luck so far. At the end of the block, I want every data pushed inside array but I am getting a blank array.
async (body, nextCall) => {
var tmpArryOfModuleList = []
var bodyData = body.data
var promise = new Promise((resolve, reject) => {
bodyData.forEach(element => {
if (element.hasCRUD === '0') {
var options = {
method: 'GET',
url: `${apiURL}/api/fetchAllCharts`,
headers:
{
Authorization: token
}
};
request(options, function (error, response, dashboardData) {
if (error) {
return nextCall({
error: error
})
}
var parsedDashboardData = JSON.parse(dashboardData)
for (var i = 0; i < parsedDashboardData['data'].length; i++) {
var val = element.name + " - " + parsedDashboardData['data'][i]['name']
var randomID = Math.random().toString(36).slice(2)
tmpArryOfModuleList.push({ "_id": randomID, "submodule": val })
}
});
} else if (element.hasCRUD == '1') {
var options = {
method: 'GET',
url: `${apiURL}/api/fetchAllActions`,
headers:
{
Authorization: token
}
};
request(options, function (error, response, crudData) {
if (error) {
return nextCall({
error: error
})
}
var parsedcrudData = JSON.parse(crudData)
for (var i = 0; i < parsedcrudData['data'].length; i++) {
var val = element.name + " - " + parsedcrudData['data'][i]['name']
var randomID = Math.random().toString(36).slice(2)
tmpArryOfModuleList.push({ "_id": randomID, "submodule": val })
}
});
} else {
console.log('no data found')
reject('No Data Found')
}
})
resolve(tmpArryOfModuleList)
})
console.log('tmpArryOfModuleList', tmpArryOfModuleList)
}
What am I doing wrong? How can I achieve the result on the last array?

Related

Async function returning existing array as undefined

I have an async function inside my class that does execute like it is supposed, but its return value is undefined when I call it. Executing console.log(array) just before the return line "return array" does work
I've tried setting up the variable in this.array but it is not working either.
class Core {
constructor(key) {
this.key = key;
}
async getSessions() {
var finalresponse = []
try {
// wait for response
await fetch("https://api.purecore.io/rest/1/session/get/?key=" + this.key, { method: "GET" }).then(function (response) {
return response.json();
}).then(function (jsonresponse) {
// looks for errors
if (jsonresponse.error != null) {
throw new Error("PureCore returned an error: " + jsonresponse.error + " -> " + jsonresponse.msg)
} else {
// adds the sessions to the response
jsonresponse.forEach(player => {
finalresponse.push(new CoreSession(player["mojang_username"], player["mojang_uuid"], player["core_id"], player["verified"]))
});
console.log(finalresponse) // returns array list
return finalresponse; // returns undefined
}
});
} catch (e) {
throw new Error("Error while getting the response for 'https://api.purecore.io/rest/1/session/get/?key=" + this.key + "' -> " + e.message)
}
}
}
class CoreSession {
constructor(username, uuid, core_uuid, verified) {
this.username = username;
this.uuid = uuid;
this.core_uuid = core_uuid;
this.verified = verified;
}
}
// testing:
sessions = new Core("731b59d106ea5acd0a385958d8e0f18b4b74b741f28f6efa43ed4a273a42d6f9").getSessions().then(function (value) {
console.log(value)
}, function (reason) {
console.log(reason)
});
I'm getting these results:
(from the chrome debug tool)
you have to return something from the async function,
// wait for response
return await fetch("https://api.purecore.io/rest/1/session/get/?key=" + this.key, { method: "GET" }).then(function (response) {
class Core {
constructor(key) {
this.key = key;
}
async getSessions() {
var finalresponse = []
try {
// wait for response
return await fetch("https://api.purecore.io/rest/1/session/get/?key=" + this.key, { method: "GET" }).then(function (response) {
return response.json();
}).then(function (jsonresponse) {
// looks for errors
if (jsonresponse.error != null) {
throw new Error("PureCore returned an error: " + jsonresponse.error + " -> " + jsonresponse.msg)
} else {
// adds the sessions to the response
jsonresponse.forEach(player => {
finalresponse.push(new CoreSession(player["mojang_username"], player["mojang_uuid"], player["core_id"], player["verified"]))
});
console.log(finalresponse) // returns array list
return finalresponse; // returns undefined
}
});
} catch (e) {
throw new Error("Error while getting the response for 'https://api.purecore.io/rest/1/session/get/?key=" + this.key + "' -> " + e.message)
}
}
}
class CoreSession {
constructor(username, uuid, core_uuid, verified) {
this.username = username;
this.uuid = uuid;
this.core_uuid = core_uuid;
this.verified = verified;
}
}
// testing:
sessions = new Core("731b59d106ea5acd0a385958d8e0f18b4b74b741f28f6efa43ed4a273a42d6f9").getSessions().then(function (value) {
console.log(value)
}, function (reason) {
console.log(reason)
});

Reading values from JSON in Node.js in GET request

I need to pull the Indication value from the following
{
"records": [{
"id": "recBgV3VDiJeMkcwo",
"fields": {
"DrugName": "azatadine",
"nameapi": ["recBgV3VDiJeMkcwo"],
"Indication": "For the relief of the symptoms of upper respiratory mucosal congestion in perennial and allergic rhinitis, and for the relief of nasal congestion and eustachian t.b. congestion.",
"lookup": ["azatadine"],
"drugID": "recBgV3VDiJeMkcwo"
},
"createdTime": "2018-11-09T19:38:24.000Z"
}]
}
When I try to do
response.records[0].fields.Indication
I get the error
Cannot read property 'fields' of undefined
Here is my code:
function httpGet() {
return new Promise(((resolve, reject) => {
var options = {
host: 'api.airtable.com',
port: 443,
path: '/v0/appYqfJ3Rt2F0sRGn/Database?filterByFormula=(DrugName=%27azatadine%27)',
method: 'GET',
headers: {
Authorization: 'Bearer key123456789'
}
};
const request = https.request(options, (response) => {
response.setEncoding('utf8');
let returnData = '';
response.on('data', (chunk) => {
returnData += chunk;
});
response.on('end', () => {
resolve(returnData);
});
response.on('error', (error) => {
reject(error);
});
});
request.end();
}));
}
const UserReplyIntent_Handler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest' && request.intent.name === 'UserReplyIntent' ;
},
async handle(handlerInput) {
const response = await httpGet();
console.log(response);
return handlerInput.responseBuilder
.speak("Okay. Here we go" + response.records[0].fields.Indication)
.reprompt("say again")
.getResponse();
},
};
Your JSON isn’t really JSON yet at this stage. You need to parse the result you get from your Ajax request to then work with it as native JSON.
The response is stringified when it gets delivered to you, that parse command will in stringify it for you.
You can do this as part of a then chain after your promise (probably best practice) or do it right inside your promise.
I was missing json.parse
.then((response) => {
const data = JSON.parse(response);
for (let i = 0; i < data.records.length; i++) {
if (i === 0) {
outputSpeech = outputSpeech + 'The name of the drug is' + data.records[i].fields.DrugName + ', '
I was missing the json.parse method
.then((response) => {
const data = JSON.parse(response);
for (let i = 0; i < data.records.length; i++) {
if (i === 0) {
outputSpeech = outputSpeech + 'The name of the drug is' + data.records[i].fields.DrugName + ', '
A standard way to do this with asynchronous responses is to do the following:
.then((response) => response.json())
.then((response) => {
//response is now a JSON object that you can be worked with
})

Return promise after multiple calls with the same instance of an Ajax method

I'm using Ajax with JQuery to fetch data from an API that only returns 100 records at a time. If my query gives a result with more than 100 records, the API will include an "offset" parameter in the response. I have to use this offset parameter in a new API call to get the next 100 records. The API will include a new offset parameter if there's even more records to fetch. And so on until all records are fetched.
As you can see I've solved this by having the function call itself until the "offset" parameter is no longer included. I.e. until there are no more records to fetch.
Because of this behavior of the API, I cannot use the Ajax method's own .done-function, since it would be executed multiple times (for each iteration of the Ajax method).
How can adjust the function below to return a promise when all Ajax calls have been done?
function getContracts(offset) {
var data = {};
if (offset !== undefined) {
data["offset"] = offset;
}
$.ajax({
url: url,
headers: {
Authorization: apiKey
},
data: data,
success: function(result){
$.each(result.records, function() {
contracts.push(this);
});
if (result.hasOwnProperty("offset")) {
getContracts(result.offset);
}
}
});
}
Real and full code as requested:
var objectContracts = [];
var landContracts = [];
var locations = [];
var customers = [];
var landOwners = [];
var frameworkAgreements = [];
function getObjectContracts(offset) {
return new Promise((resolve, reject) => {
var data = {};
data["view"] = 'Alla Objektsavtal';
if (offset !== undefined) {
data["offset"] = offset;
}
$.ajax({
url: url + "Objektsavtal",
headers: {
Authorization: apiKey
},
data: data,
success: function(result){
$.each(result.records, function() {
objectContracts.push(this);
});
if (result.hasOwnProperty("offset")) {
getObjectContracts(result.offset);
} else {
resolve();
}
}
});
});
}
function getLandContracts(offset) {
return new Promise((resolve, reject) => {
var data = {};
data["view"] = 'Alla Markavtal';
if (offset !== undefined) {
data["offset"] = offset;
}
$.ajax({
url: url + "Markavtal",
headers: {
Authorization: apiKey
},
data: data,
success: function(result){
$.each(result.records, function() {
landContracts.push(this);
});
if (result.hasOwnProperty("offset")) {
getLandContracts(result.offset);
} else {
resolve();
}
}
});
});
}
function getLocations(offset) {
return new Promise((resolve, reject) => {
var data = {};
data["view"] = 'Alla Uppställningsplatser';
if (offset !== undefined) {
data["offset"] = offset;
}
$.ajax({
url: url + "Uppställningsplatser",
headers: {
Authorization: apiKey
},
data: data,
success: function(result){
$.each(result.records, function() {
locations.push(this);
});
if (result.hasOwnProperty("offset")) {
getLocations(result.offset);
} else {
resolve();
}
}
});
});
}
function getCustomers(offset) {
return new Promise((resolve, reject) => {
var data = {};
data["view"] = 'Alla Kunder';
if (offset !== undefined) {
data["offset"] = offset;
}
$.ajax({
url: url + "Kunder",
headers: {
Authorization: apiKey
},
data: data,
success: function(result){
$.each(result.records, function() {
customers.push(this);
});
if (result.hasOwnProperty("offset")) {
getCustomers(result.offset);
} else {
resolve();
}
}
});
});
}
function getLandOwners(offset) {
return new Promise((resolve, reject) => {
var data = {};
data["view"] = 'Alla Markägare';
if (offset !== undefined) {
data["offset"] = offset;
}
$.ajax({
url: url + "Markägare",
headers: {
Authorization: apiKey
},
data: data,
success: function(result){
$.each(result.records, function() {
landOwners.push(this);
});
if (result.hasOwnProperty("offset")) {
getLandOwners(result.offset);
} else {
resolve();
}
}
});
});
}
function getFrameworkAgreements(offset) {
return new Promise((resolve, reject) => {
var data = {};
data["view"] = 'Alla Ramavtal';
if (offset !== undefined) {
data["offset"] = offset;
}
$.ajax({
url: url + "Ramavtal",
headers: {
Authorization: apiKey
},
data: data,
success: function(result){
$.each(result.records, function() {
frameworkAgreements.push(this);
});
if (result.hasOwnProperty("offset")) {
getFrameworkAgreements(result.offset);
} else {
resolve();
}
}
});
});
}
If I've understood your question perfectly, you want to resolve a Promise if there is no offset in the response from your Ajax request.
I haven't tested this code but you can do something like this:
function getContracts(offset) {
return new Promise((resolve, reject) => {
var data = {};
if (offset !== undefined) {
data['offset'] = offset;
}
$.ajax({
url: url,
headers: {
Authorization: apiKey,
},
data: data,
success: function(result) {
$.each(result.records, function() {
contracts.push(this);
});
if (result.hasOwnProperty('offset')) {
getContracts(result.offset);
} else {
// I guess this is what you want
// If there is no offset property => resolve the promise
resolve('Your result goes here');
}
},
});
});
}
See the else block.
You can pass your final result (whatever you want to achieve after the completion of your task) inside the resolve. For example, you can create an array and append your result to that and at the end, you can pass that array inside resolve.
You can resolve this using .then() or async/await
async () => {
const result = await getContracts(offset);
};
or
getContracts(offset).then(result => { console.log(result) });
If you see some Unhandled Promise Rejection warning/error, you can always use try/catch block with async/await and .catch after .then.
EDIT:
First, you're not passing anything inside resolve. Whatever you pass inside the resolve will be reflected in .then(result).
Second, you have global variables and storing all your data inside them. So now you don't need to pass them inside the resolve but this is not a good approach because any function or the code outside can modify it. So I'll give you one example.
function getObjectContracts(offset) {
return new Promise((resolve, reject) => {
var data = {};
const objectContracts = [];
data['view'] = 'Alla Objektsavtal';
if (offset !== undefined) {
data['offset'] = offset;
}
$.ajax({
url: url + 'Objektsavtal',
headers: {
Authorization: apiKey,
},
data: data,
success: function(result) {
$.each(result.records, function() {
objectContracts.push(this);
});
if (result.hasOwnProperty('offset')) {
getObjectContracts(result.offset);
} else {
resolve(objectContracts);
}
},
});
});
}
Now, the other question is, how to resolve all these promises at once.
const finalFunction = async () => {
const [result1, result2, result3] = await Promise.all([
getObjectContracts(offset1),
getLandContracts(offset2),
getLocations(offset3),
]);
console.log(result1, result2, result3);
};
finalFunction();

How to Loop Through API Calls

I am trying to loop through coordinates of an API endpoint and test each response. When I send the request when it is not nested in for loops it works just fine, however, it doesn't seem to send when nested.
How can I automate the testing of this endpoint with various coordinates?
const request = require('request')
const domain = 'host.local'
const port = '8085'
const url = 'http://' + domain + ':' + port + '/v1/vend/item'
const parameters = {
coordinate: {
x: null,
y: null
},
network: {
user: "config",
role: "admin"
}
}
const x_coordinates = [1,2,3,4,5]
const y_coordinates = [6,7,8,9,10]
let options = {
method: 'post',
body: parameters,
json: true,
url: url
}
for (item in x_coordinates) {
parameters.coordinate.x = parseInt(item) + 1
for (item in y_coordinates.length) {
parameters.coordinate.y = parseInt(item) + 7
sleep(10000)
request(options, (err, res, body) => {
var headers = res.headers
var statusCode = res.statusCode
})
}
}
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break
}
}
}
Alternative promise method
for(let i=0; i<x_coordinates.length; i++) {
body.coordinate.x = i
for(let j=0; j<y_coordinates.length; j++) {
body.coordinate.y = j
let options = {
url: 'http://' + domain + ':' + port + '/v1/vend/item',
method: 'post',
json: true,
body: body
}
ps.push(rp(options))
}
}
Promise.all(ps)
.then((results) => {
console.log(results)
})
.catch(err => {
console.log(err)
})
This implementation of promises sent all the requests at once. They need a delay between them. Ideally, once the first request gets a response, the second is sent.
I like to use a little helper function called chainAsync:
https://github.com/30-seconds/30-seconds-of-code#chainasync
Here it is written a bit less densely:
function chainAsync(arrayOfFunctions){
let currentFunctionIndex = 0
const lastFunction = arrayOfFunctions[arrayOfFunctions.length - 1]
goToNextFunction()
function goToNextFunction(){
const currentFunction = arrayOfFunctions[currentFunctionIndex]
if(currentFunction == lastFunction){
currentFunction()
}else{
currentFunction(goToNextFunction)
currentFunctionIndex += 1
}
}
}
You can use it like this:
chainAsync([
function(goToNextFunction){
request(options, (err, res, body)=>{
// Handle the response. Then...
goToNextFunction()
})
},
function(goToNextFunction){
request(options, (err, res, body)=>{
// Handle the response. Then...
goToNextFunction()
})
},
function(){
request(options, (err, res, body)=>{
// Handle the response. Then...
// ...don't go to next function, since there isn't a next function!
})
}
])
This way you have control over the order in which these asynchronous functions take place.
Here's one way of using it to address your use-case:
const requestsToExecute = []
x_coordinates.forEach(x=>{
y_coordinates.forEach(y=>{
const currentRequest = function(goToNextRequest){
const requestOptions = {
url: 'http://host.local:8085/v1/vend/item',
method: 'POST',
json: true,
body: {
coordinate: {x, y},
network: {
user: 'config',
role: 'admin'
}
}
}
request(requestOptions, (err, response, body)=>{
// Handle the response, then...
// ...if there's another request...
if(goToNextRequest){
// ...use setTimeout to wait 1e7 seconds before going to the next request
setTimeout(goToNextRequest, 1e7)
}
})
}
requestsToExecute.push(currentRequest)
})
})
chainAsync(requestsToExecute)

javascript promise callback

I am calling a javascript function , which in turn calls a web service;The response of this service is used to call another function which also calls a service. At end of both services we set session attributes. This code gives no errors, but the callback gets called before the service has returned data. The main motive of this code is to set the session attributes before return of flow from this code, when the callback gets called before the service has returned values the session attributes are not set and the requirement of the code is not fulfilled.
'use strict';
function close(sessionAttributes, fulfillmentState, message) {
return {
sessionAttributes,
dialogAction: {
type: 'Close',
fulfillmentState,
message : 'For security purpose answer these questions '
},
};
}
function getSecurityQuestions(intentRequest, context, post_options, callback){
const sessionAttributes = intentRequest.sessionAttributes || {};
var policynumber = sessionAttributes.policynumber;
var interactionID = sessionAttributes.interactionID;
var body = "";
var body2;
const http = require('https');
const promise = new Promise((resolve, reject) => {
const post_data = JSON.stringify({"Purpose":"SecurityQuestions", "InteractionID":interactionID, "SearchStringAcctNum":policynumber});
//ignores SSL
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
var post_request = http.request(post_options, function(res) {
res.on('data', function(chunk) {
body += chunk;
});
res.on('end', function() {
context.done(body);
resolve(body);
});
res.on('error', function(e) {
reject(Error(e.message));
context.fail('error:' + e.message);
});
});
// post the data
post_request.write(post_data);
post_request.end();
});
callback( promise.then((body) => {
body2 = JSON.parse(body);
sessionAttributes.question1 = body2.SecurityDetails[0].Question;
close(sessionAttributes, 'Fulfilled');
}, (error) => {
console.log(error.message);
})
);
}
function getInteraction(intentRequest, context, callback) {
const slots = intentRequest.currentIntent.slots;
var policynumber = "PA"+slots.PolicyNumber;
var questionOne = slots.questionOne;
var questionTwo = slots.questionTwo;
const sessionAttributes = intentRequest.sessionAttributes || {};
console.log("policy number : "+policynumber + "question 1 : "+questionOne + "question 2 : "+questionTwo);
sessionAttributes.policynumber = policynumber;
var body = "";
var body2;
// An object of options to indicate where to post to
var post_options = {
host: 'example.com',
protocol: 'https:',
port: '3000',
path: '/hiddenPath',
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
const http = require('https');
const promise = new Promise((resolve, reject) => {
const post_data = JSON.stringify({"Purpose":"CreateInteraction"});
//ignores SSL
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
var post_request = http.request(post_options, function(res) {
res.on('data', function(chunk) {
body += chunk;
});
res.on('end', function() {
context.done(body);
resolve(body);
});
res.on('error', function(e) {
console.log("rejected here");
reject(Error(e.message));
context.fail('error:' + e.message);
});
});
// post the data
post_request.write(post_data);
post_request.end();
});
callback( promise.then((body) => {
body2 = JSON.parse(body);
console.log("interaction ID : "+body2.InteractionID);
sessionAttributes.interactionID = body2.InteractionID;
getSecurityQuestions(intentRequest, context, post_options, callback);
}, (error) => {
console.log('Promise rejected.');
console.log(error.message);
}));
}
// --------------- Intents -----------------------
/**
* Called when the user specifies an intent for this skill.
*/
function dispatch(intentRequest, context, callback) {
const intentName = intentRequest.currentIntent.name;
if (intentName === 'currIntent') {
return getInteraction(intentRequest, context, callback);
}
throw new Error(`Intent with name ${intentName} not supported`);
}
// --------------- Main handler -----------------------
function loggingCallback(response, originalCallback) {
console.log("logging callback called......");
originalCallback(null, response);
}
exports.handler = (event, context, callback) => {
try {
dispatch(event, context, (response) => loggingCallback(response, callback));
} catch (err) {
callback(err);
}
};
You should resolve your promise only after the request ends.. Have updated your sample below. Hope it helps. Also, you were sending an invalid object as your post body. Fixed that as well.
function getValue(context, post_options, callback) {
var body = "";
var body2;
const http = require('http');
const promise = new Promise((resolve, reject) => {
// INVALID OBJECT
//const post_data = JSON.stringify({"something"});
const post_data = JSON.stringify({
something: "something"
});
//ignores SSL
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
var post_request = http.request(post_options, function(res) {
res.on('data', function(chunk) {
body += chunk;
console.log("inside " + JSON.stringify(body));
// DONT RESOLVE HERE, REQUEST IS NOT COMPLETE
//resolve(body);
});
res.on('end', function() {
context.done(body);
//RESOLVE HERE INSTEAD
resolve(body);
});
res.on('error', function(e) {
reject(Error(e.message));
context.fail('error:' + e.message);
});
});
// post the data
post_request.write(post_data);
post_request.end();
});
promise.then((body) => {
console.log("response data " + JSON.stringify(body));
body2 = JSON.parse(body);
callback(delegate(sessionAttributes, intentRequest.currentIntent.slots));
}, (error) => {
console.log('Promise rejected.');
console.log(error.message);
});
}

Categories

Resources