Background: I have a function that needs a small debugging which is related to API requests(POST,GET) and promises. For the past few days, I have been trying to figure how asynchronous functions work and it turns out it's impossible (or so I heard) to directly return a value from such functions to synchronous functions.
My initial idea was to make a POST request function that returns an access token which I could plug to the authorization header of my GET function (which works perfectly so long as a token is provided). From my discovery, however, I can't do this on two separate methods because the POST request returns undefined outside the function. So my idea now is to include the GET request within the POST so that the access token can be passed directly without any method call. I tried to do this using Promises which I'm not very familiar with but manage to make some sense. My expectation was that I can call the httpGetData() function which would first get token, then pass it to a .then() portion which is supposed to return actual data or [object Promise] instead of undefined.
Question: The issue is that when I call the httpGetData() function it returns undefined but my console.log(result[0]) shows clearly that the GET request has fetched the data I want. I was wondering if there is a tweak that would allow my code to return this data (console.log is useless for me other than to see what's happening on background of api request). I saw some SO questions like these answered by returning the values in the .then() but my attempts all return undefined.
I've attached screenshots of the outputs. Keep in mind this is an Alexa skill Lambda code so the return appears after .speak() and the console.log shows below.
function httpGetData() {
var promise1 = new Promise(((resolve, reject) => {
var options = {
method: "POST", // POST request intended to get access token
host: 'hostinfo',
path: "pathinfo",
headers: {
"content-type": "stuff here",
"cache-control": "no-cache",
}
};
var request = http.request(options, function (response) {
var returnData = [];
response.on("data", function (chunk) {
returnData += chunk;
});
response.on("end", function () {
var data = JSON.parse(returnData);
var accessToken = data.access_token; // the access token value of the POST api request like "039509544932n3249fc21232nc32423nci"
resolve(accessToken);
});
response.on('error', (error) => {
reject(error);
});
});
request.write("------stuff: form-data; name=\"client_secret\"\r\n\r\stuff here\r\n------stuff: form-data; name=\"client_id\"\r\n\r\stuff here\r\n------stuff: form-data; name=\"grant_type\"\r\n\r\nclient_credentials\r\n------stuff");
request.end();
}));
promise1.then(function(value) {
return new Promise(((resolve, reject) => {
var options = {
method: "GET", //this is a GET request so it's intended to get usable data using access token
host: 'hostinfo',
path: "pathinfo",
headers: {
"content-type": "stuff here",
"Authorization": "Bearer " + value, // value is the access token that was resolved earlier ("039509544932n3249fc21232nc32423nci") so I'm trying to concatonate this to the authorization header
"cache-control": "no-cache",
}
};
var request = http.request(options, function (response) {
var returnData = [];
response.on("data", function (chunk) {
returnData += chunk;
});
response.on("end", function () {
console.log(value); //this is the line that prints access token in screenshot
resolve(JSON.parse(returnData));
});
response.on('error', (error) => {
reject(error);
});
});
request.write("------stuff: form-data; name=\"client_secret\"\r\n\r\stuff here\r\n------stuff: form-data; name=\"client_id\"\r\n\r\stuff here\r\n------stuff: form-data; name=\"grant_type\"\r\n\r\nclient_credentials\r\n------stuff");
request.end();
}))
}).then((result) => {
console.log('hello');
return result; //I'm not sure here but wanted to return the result
}).then((result) => {
console.log(result[0]); // just a check which shows that result[0] actually executes and can be printed as shown in screenshot
return result[0]; //other desperate attempt
});
}// httpGetData() function ends here
return image
Console log image
I've finally solved the problem thanks to @Bergi. Although this answer can be shortened, I want to post it so that it can serve as an option. What Bergi suggested was that instead of having both the POST and GET requests done in one function, we can separate them and use another function to do execute them simultaneously. In the code below, httpToken() performs the POST request and returns an access token. The httpResource(accessToken) function performs a GET request where it will take an accessToken parameter. The other function, finalData() will help us make the POST and GET requests simultaneously hence returning an [object Promise] instead of undefined, which we can access. Our last step will be to have an async/await function (retrieveInfo()), which will use finalData() to get the response from our requests. Enjoy!
function httpToken() {
return new Promise(((resolve, reject) => {
var options = {
method: "POST",
host: 'hostinfo',
path: "pathinfo",
headers: {
"content-type": "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
"cache-control": "no-cache",
}
};
var request = http.request(options, function (response) {
var returnData = [];
response.on("data", function (chunk) {
returnData += chunk;
});
response.on("end", function () {
var data = JSON.parse(returnData);
var accessToken = data.access_token;
resolve(accessToken); //resolving access token (can be changed to resolve(data) to include timestamp etc)
});
response.on('error', (error) => {
reject(error);
});
});
request.write("------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"client_secret\"\r\n\r\n"client secret here"\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"client_id\"\r\n\r\n"client id here"\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"grant_type\"\r\n\r\n"grant type here"\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--");
request.end();
}));
}
function httpResource(accessToken){
return new Promise(((resolve, reject) => {
var options = {
method: "GET",
host: 'hostinfo',
path: "pathinfo",
headers: {
"content-type": "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
"Authorization": "Bearer " + accessToken,
"cache-control": "no-cache",
}
};
var request = http.request(options, function (response) {
var returnData = [];
response.on("data", function (chunk) {
returnData += chunk;
});
response.on("end", function () {
resolve(JSON.parse(returnData));
});
response.on('error', (error) => {
reject(error);
});
});
request.write("------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"client_secret\"\r\n\r\n"client secret here"\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"client_id\"\r\n\r\n"client id here"\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW\r\nContent-Disposition: form-data; name=\"grant_type\"\r\n\r\n"grant type here"\r\n------WebKitFormBoundary7MA4YWxkTrZu0gW--");
request.end();
}));
}
function finalData()
{
return httpToken().then(token => httpResource(token));
}
async function retrieveInfo()
{
response = await finalData(); //response will have the data returned from our GET request using finalData()
//do stuff with response...
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With