The previous question was marked as a duplicate, with the link leading me here: How do I return the response from an asynchronous call?.
I still couldn't find a solution, but I guess i will need AJAX to return this object, because my functions/GET Request hasn't completed, which leads me to a new question. How can I adapt this to return asynchronously. I understand the concepet of Promises and async/await, but I'm unsure how I can implement this here so I can access the object globally.
[Original Question]
Returning object from the below function, but I'm receiving this error ReferenceError: object is not defined. I would like to access this globally, but can't seem to access the object because of scope. Is there something that I'm missing?
When setting a global variable, this doesn't seem to update.
For example setting var globalObject = {}; outside and using globalObject = object inside the object doesn't seem to change the variable {}
function getTicket (ticketID) {
var urlID = contentID;
var request = require("request");
var options = {
method: 'GET',
url: `https://www.mywebsite.com/api/${urlID}/body.json`,
headers: {'content-type': 'application/json', authorization: 'Basic PASSWORD=='}
};
request(options, function (response, body) {
var obj = JSON.parse(JSON.stringify(body));
var objContent = JSON.parse(obj.body);
var object = {
id: urlID,
url: 'https://www.mywebsite.com/api/' + urlID,
value: objContent
};
console.log(object.id);
console.log(object.url);
console.log(objContent.body[0].body);
});
return object;
}
getTicket(380289);
You can convert your function to return a promise and then use await when calling it:
function getTicket(ticketID) {
var urlID = contentID;
var request = require('request');
var options = {
method: 'GET',
url: `https://www.mywebsite.com/api/${urlID}/body.json`,
headers: { 'content-type': 'application/json', authorization: 'Basic PASSWORD==' }
};
return Promise(resolve => {
request(options, function(response, body) {
var obj = JSON.parse(JSON.stringify(body));
var objContent = JSON.parse(obj.body);
var object = {
id: urlID,
url: 'https://www.mywebsite.com/api/' + urlID,
value: objContent
};
console.log(object.id);
console.log(object.url);
console.log(objContent.body[0].body);
resolve(object);
});
});
}
await getTicket(380289);
Note that your call will need to happen in an async scope. If you are in the global scope, you can use:
(async function() {
await getTicket(380289);
})();
See using await on global scope without async keyword for more details
Related
I've got an 11ty project (static site generator) where I'm fetching property data then using this data in a Promise.all call to:
fetch all property images and
fetch tenancy application urls
Then add these into one array labeled allData for my pages.
Image call is working fine but the tenancy api call is not.
I'm changing the api body I'm sending to to the tenancy api by using the i from Promise.all and this seems to be working from my console.logs but the result I'm getting is the same tenancy link being returned for each call.
I feel like it might have something to do with the order I'm calling fetch/using Promise.all because if I add a hello console log my an array with i label will log followed by hello, then the next e.g. body 1 hello, body 2 hello, etc. and then all the tpResponses (urls) will log in a row.. which doesn't seem right. I can't see the actual requests going through since this is done in build time so I'm a little confused but I'm guessing only one apibody is being sent based on results.
I've tried using .then for the fetch calls but think I configured this wrong. Do I need to use .then for the fetch calls or something other than Promise.all and how would that work?
Code below. Any help would be appreciated!
require('dotenv').config();
const EleventyFetch = require("#11ty/eleventy-fetch");
const crypto = require('crypto');
async function getPropertyData(){
console.log("getPropertyData...")
//Property vars
var username = process.env.MANOR_USERNAME;
var password = process.env.MANOR_PASSWORD;
var auth = 'Basic ' + Buffer.from(username + ':' + password).toString('base64');
//Tenancy vars
var api_public_key = process.env.TPS_KEY;
var api_secret = process.env.TPS_SECRET
let api_url = "https://www.tpsportal.co.nz/api/v1/tenancy_application/create_property"
function sign(endpoint, key, secret, date, body) {
const encoded = new
Buffer([endpoint,body,date].join('\n')).toString('base64');
return crypto
.createHash('sha256')
.update(encoded + '+' + secret, 'utf8')
.digest()
.toString('hex');
}
//Get Property Details
const url = `https://api.getpalace.com/Service.svc/RestService/v2AvailableProperties/JSON`
const response = EleventyFetch(url, {
duration: "1d",
type: "json",
fetchOptions: {
headers: {
accept: 'application/json',
'content-type': 'application/json',
'Authorization': auth
}
}
})
const properties = await response;
//Create URLs for Image call
let propertyImageUrls = []
properties.forEach(property => {
propertyImageUrls.push(`https://api.getpalace.com/Service.svc/RestService/v2AvailablePropertyImagesURL/JSON/${property.PropertyCode}`)
});
let allData = [];
//Fetch Property Images
const allPropertyImages = await Promise.all(propertyImageUrls.map(async (url,i) => {
const imageResponse = await EleventyFetch(url, {
duration: "1d",
type: "json",
fetchOptions: {
headers: {
accept: 'application/json',
'content-type': 'application/json',
'Authorization': auth
}
}
});
let tpData;
const imageData = await imageResponse;
//Add property matching details + image to allData array
let apibody = JSON.stringify({
client_code: "8754",
property_code: properties[i].PropertyCode,
agent_name: properties[i].PropertyAgent.PropertyAgentFullName,
agent_email: properties[i].PropertyAgent.PropertyAgentEmail1,
unit: properties[i].PropertyUnit,
street_number: properties[i].PropertyAddress1,
street_name: properties[i].PropertyAddress2,
suburb: properties[i].PropertyAddress3,
city: properties[i].PropertyAddress4,
postcode: properties[i].PropertyFeatures.PropertyPostCode
})
console.log("API BODY " + i +" :",apibody)
var api_date = new Date().toISOString();
var signature = sign(api_url,api_public_key,api_secret,api_date,apibody)
console.log('hello')
let tpResponse = await EleventyFetch(api_url, {
duration: "1d",
type: "json",
fetchOptions: {
method: 'post',
headers: {
accept: 'application/json',
'content-type': 'application/json',
'X-API-DATE': api_date,
'X-API-KEY': api_public_key,
'X-API-SIGNATURE': signature
},
body: apibody
}
})
console.log("tpResponse: ", apibody)
tpData = await tpResponse;
console.log("tpData: ", tpData)
This is the error: tpData is just giving me the same link for each property instead of different links
allData.push([properties[i], imageData, tpData])
}))
// console.log(allData)
return allData;
}
module.exports = getPropertyData;
This question already has answers here:
async/await always returns promise
(4 answers)
Closed 2 months ago.
I'm really confused about asynchronous functions in general, but I can't seem to return what the api has fetched. Using console.log() gives all the results but I need the function's path (array) for later use.
function callRelation(id) {
(async () => {
const api = await fetch(
"https://www.overpass-api.de/api/interpreter?",
{
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: "[out:json];rel(" + id + ");(._;>;);out;",
},
);
const request = await api.json();
let path = [];
for (let pair of request.elements){
if (pair.type === "node"){
path.push([pair.lat, pair.lon]);
}
}
console.log(path)
return path;
})();
}
let test = callRelation(10000);
console.log(test);
I've tried using something called a callback, but I failed miserably at that.
You await to get return from promise function.
async function callRelation(id) {
const api = await fetch("https://www.overpass-api.de/api/interpreter?", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: "[out:json];rel(" + id + ");(._;>;);out;",
});
const request = await api.json();
let path = [];
for (let pair of request.elements) {
if (pair.type === "node") {
path.push([pair.lat, pair.lon]);
}
}
console.log(path);
return path;
}
(async function () {
let test = await callRelation(10000);
console.log(test);
})();
I'm trying to send multiple HTTP requests from my node.js server (using the 'request' package) in a for loop.
The idea is to basically have an array of URLs, send a HTTP get for each one, and store the response in an array called 'responseArray'.
When I try this, I get 'undefined', but I know the requests are working if I log them to the console inside the for loop.
function apiCalls() {
var URLs = [‘URL1’, ‘URL2’, ‘URL3’];
var responseArray = []
for (var i = 0; i < URLs.length; i++) {
request({
url: URLs[i],
method: 'GET',
headers: {
'Connection': 'close'
},
}, function(error, response, body) {
if (error) {
console.log(error);
} else {
responseArray.push(String(response.body));
console.log(responseArray) // this is showing me all the data in the array correctly
return responseArray;
}
}) //end request function
} //end for loop
console.log(responseArray)
} //end apiCalls function
apiCalls()
So after looking at a few different solutions here on stack overflow and elsehwere I tried using promises. I've never used them before and based this off the google example
Promise:
var apiCalls = new Promise(function(resolve, reject) {
var URLs = [‘URL1’, ‘URL2’, ‘URL3’];
var responseArray = [];
for (var i = 0; i < URLs.length; i++) {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
request({
url: URLs[i],
method: 'GET',
headers: {
'Connection': 'close'
},
}, function(error, response, body) {
if (error) {
console.log(error);
} else {
resolve(responseArray.push(String(response.body))
}
}) //end request
} //end for loop
})
apiCalls.then(function(result) {
console.log('this is calling the promise')
console.log(result)
}, function(err) {
console.log(err)
});
I always get an empty array when I try to log the responseArray after the for loop. Alternatively - I get 'undefined' if I try to assign the returned array to a variable like so:
var gimmeAllResponses = apiCalls();
console.log(gimmeAllResponses); //returns 'undefined'
Can anyone show me where I'm going wrong? how do I updated the 'responseArray' data after the for loop has finished?
This is a little bit off, since this requires the alternative package, request-promise.
You're resolving many times. Since you're using Node.js, it's very likely that ES6 features are available. Use Array.prototype.map() and Promise.all():
var rp = require('request-promise');
var URLs = [‘URL1’, ‘URL2’, ‘URL3’];
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
var responseArray = Promise.all(URLs.map((url) => rp({
uri: url,
method: 'GET',
headers: {
'Connection': 'close'
}
}).then((error, response, body) => {
if (error) {
console.log(error);
} else {
return String(response.body);
}
})));
If the first REST function execute with sucess, the second it will be execute with the parameters of the first function, in the case return: sessionid and I save the value inside variable sessionid
Both functions are REST call within the same .js file.
In the case I trying:
My restApiCall.js file:
var Client = require('./lib/node-rest-client').Client;
var client = new Client();
var dataLogin = {
data: { "userName":"xxxxx","password":"xxxxxxxxxx","platform":"xxxx" },
headers: { "Content-Type": "application/json" }
};
var numberOrigin = 350;
client.registerMethod("postMethod", "xxxxxxxxxxxxxxxxxx/services/login", "POST");
client.methods.postMethod(dataLogin, function (data, response) {
// parsed response body as js object
// console.log(data);
// raw response
if(Buffer.isBuffer(data)){
data = data.toString('utf8');
console.log(data);
re = /(sessionID: )([^,}]*)/g;
match = re.exec(data);
var sessionid = match[2]
console.log(sessionid);
openRequest(sessionid, numberOrigin); // I try execute, but just the first execute if I type inside Prompt command: node restApiCall
}
});
// this is the second function I want execute after the first sucess
function openRequest(sessionid, numberOrigin){
var client = new Client();
numberOrigin+=1;
var dataRequest = {
data: {"sessionID":sessionid,"synchronize":false,"sourceRequest":{"numberOrigin":numberOrigin,"type":"R","description":"Test - DHC","userID":"xxxxxxxxxx","contact":{"name":"Sayuri Mizuguchi","phoneNumber":"xxxxxxxxxx","email":"xxxxxxxxxxxxxxxxxx","department":"IT Bimodal"},"contractID":"1","service":{"code":"504","name":"Deve","category":{"name":"Developers"}}} },
headers: { "Content-Type": "application/json" }
};
client.post("xxxxxxxxxxxxxxxxxxxxxxxxx/services/request/create", dataRequest, function (data, response) {
// parsed response body as js object
// console.log(data);
// raw response
console.log(response);
});
}
Thanks advance.
In the case the problem is new Client(); because the client have definied with line 2 and dont necessary declare again.
I use this code and works fine.
var Client = require('./lib/node-rest-client').Client;
var client = new Client(); //defined
var dataLogin = {
data: { "userName":"xxxxx","password":"xxxxxxxxxx","platform":"xxxx" },
headers: { "Content-Type": "application/json" }
};
var numberOrigin = 350;
client.registerMethod("postMethod", "xxxxxxxxxxxxxxxxxx/services/login", "POST");
client.methods.postMethod(dataLogin, function (data, response) {
// parsed response body as js object
// console.log(data);
// raw response
if(Buffer.isBuffer(data)){
data = data.toString('utf8');
console.log(data);
re = /(sessionID: )([^,}]*)/g;
match = re.exec(data);
var sessionid = match[2]
console.log(sessionid);
openRequest(sessionid, numberOrigin); // execute fine
}
});
function openRequest(sessionid, numberOrigin){
numberOrigin+=1;
var dataRequest = {
data: {"sessionID":sessionid,"synchronize":false,"sourceRequest":{"numberOrigin":numberOrigin,"type":"R","description":"Test - DHC","userID":"xxxxxxxxxx","contact":{"name":"Sayuri Mizuguchi","phoneNumber":"xxxxxxxxxx","email":"xxxxxxxxxxxxxxxxxx","department":"IT Bimodal"},"contractID":"1","service":{"code":"504","name":"Deve","category":{"name":"Developers"}}} },
headers: { "Content-Type": "application/json" }
};
client.post("xxxxxxxxxxxxxxxxxxxxxxxxx/services/request/create", dataRequest, function (data, response) {
// parsed response body as js object
// console.log(data);
// raw response
console.log(data);
});
}
I am working on an angular app where I want to integrate OfflineJS functionality.
I have created a general service for getting and posting data to/from an API,and a specific service for each module.
Here is the code
app.service('MethodProvider', function ($http) {
var self = this;
self.get = function (url) {
var obj = {
url: url,
method: 'GET',
async: true,
headers: {
'Content-Type': 'application/json'
}
};
return $http(obj);
};
self.post = function (url, data) {
var obj = {
url: url,
method: 'POST',
async: true,
data: JSON.stringify(data),
headers: {
'Content-Type': 'application/json'
}
};
return $http(obj);
};
self.put = function (url, data) {
var obj = {
url: url,
method: 'PUT',
async: true,
headers: {
'Content-Type': 'application/json'
}
};
if (typeof data != 'undefined' && data != null) {
obj.data = JSON.stringify(data);
}
return $http(obj);
};
self.delete = function (url) {
var obj = {
url: url,
method: 'POST',
async: true,
headers: {
'Content-Type': 'application/json'
}
};
return $http(obj);
};
return self;
});
And a specific module service like User module
app.service('UserSrvc', function (MethodProvider) {
var self = this;
self.create = function (data) {
var url = apiUrl + '/user/add';
return MethodProvider.post(url, data);
};
return self;
});
How do I integrate OfflineJS in this code , I want to intercept HTTP request when network connectivity is down and resume requests when network connectivity is up . I have studied this example but unable to integrate this in angular need an example to get started.
hope this helps the future users:
Offlinejs adds Offline object to the global window object.
Offlinejs does not trigger check() by itself (it does it once if checkOnLoad option is set to true).
You may call Offline.check() just before you make an ajax request to your server and check for connection.
You can also do polling, if your app is xhr intensive.
var run = function(){
if(Offline.state=="up")
Offline.check();
};
setInterval(run, 20000); // check after 20sec
Offline.on('down',function(){ /**code to handle network down*/ });
As pointed by #Adnan Umer You need to set Offline.options = { interceptRequests: true, requests: true }
to intercept failed requests and try again once connection is back.
One caveat here is that the requests resent by Offline will be out of the scope of Angular, accordingly, all the GET requests will result to nothing. Which is actually fine, usually the user initiates the get requests.
Offline.options = {
checks: {xhr: {url: "put_url_to_check_status_of_your_server"}}
}
By default, Offlinejs checks for favicon.ico.