I’m trying to return the result object of a request but had no luck and I don’t know what I’m doing wrong.
The function works ok, but I have to remove the API keys (cause I can’t regen them).
//Import the below modules using "npm i -save request oauth-1.0a crypto"
const request = require('request')
const OAuth = require('oauth-1.0a')
const crypto = require('crypto') // depenency package for OAuth-1.0a
let myBody;
// Token request function
function generateToken() {
// #1 Initialize OAuth with your HERE OAuth credentials from the credentials file that you downloaded above
const oauth = OAuth({
consumer: {
key: 'xxxx', //Access key
secret: 'xxxx-xxxxx', //Secret key
},
signature_method: 'HMAC-SHA256',
hash_function(base_string, key) {
return crypto
.createHmac('sha256', key)
.update(base_string)
.digest('base64')
},
});
// #2 Building the request object.
const request_data = {
url: 'https://account.api.here.com/oauth2/token',
method: 'POST',
data: { grant_type: 'client_credentials' },
};
// #3 Sending the request to get the access token
request(
{
url: request_data.url,
method: request_data.method,
form: request_data.data,
headers: oauth.toHeader(oauth.authorize(request_data)),
},
function (error, response, body) {
if (response.statusCode == 200) {
result = JSON.parse(response.body);
myBody = result;
}
}
);
}
// Calling this function to get the access token
generateToken();
console.log(myBody);
Why myBody returns undefined??
Any ideas? Any help would be very appreciated.
Thanks.
Because the only place you’re assigning a value to myBody is if the response.statusCode is 200. You must not be returning a 200 there.
Thanks for the response, that’s what I thought too, but if I add a console.log(result)
It returns everything that I want, so the function is meeting a status 200.
Thanks.
Sorry for the brief reply, I’m on the hop.
I’d say that it’s because of the asynchronous request inside the generateToken
function.
The console log is likely running before the generateToken
function has assigned a value to myBody
.
You can test this using a setTimeout
, i.e.:
setTimeout(() => { console.log(myBody); }, 3000);
To fix, you probably want to mark the generateToken
function as async
and await the result of the network request.
I’m interested in async just to learn how to code properly. Cause this call takes milliseconds to be completed and adding a timeout I think it would be a patch that in a long term will be worse.
I have read many tutorials with async but do not understand how to apply it to my use case.
Thanks.
Please quickly try the thing with setTimeout
to confirm that is indeed the issue.
Ok cool. I’ve got to head out now for the evening, I’m afraid.
In the meantime you can read this which explains the problem and solution pretty well.
Then, I’ll post a longer answer tomorrow explaining how I would tackle things.
1 Like
Your other option would be to return a value through the method and work with that result.
//Import the below modules using "npm i -save request oauth-1.0a crypto"
const request = require('request')
const OAuth = require('oauth-1.0a')
const crypto = require('crypto') // depenency package for OAuth-1.0a
let myBody;
// Token request function
function generateToken() {
let result;
// #1 Initialize OAuth with your HERE OAuth credentials from the credentials file that you downloaded above
const oauth = OAuth({
consumer: {
key: 'xxxx', //Access key
secret: 'xxxx-xxxxx', //Secret key
},
signature_method: 'HMAC-SHA256',
hash_function(base_string, key) {
return crypto
.createHmac('sha256', key)
.update(base_string)
.digest('base64')
},
});
// #2 Building the request object.
const request_data = {
url: 'https://account.api.here.com/oauth2/token',
method: 'POST',
data: { grant_type: 'client_credentials' },
};
// #3 Sending the request to get the access token
request(
{
url: request_data.url,
method: request_data.method,
form: request_data.data,
headers: oauth.toHeader(oauth.authorize(request_data)),
},
function (error, response, body) {
if (response.statusCode == 200) {
result = JSON.parse(response.body);
}
}
);
return result;
}
// Calling this function to get the access token
myBody = generateToken();
console.log(myBody);
I have tried the suggested answer and I get undefined. Thanks
ugh. that’s true for the same reason James gave you…I was thinking the function would wait, but it won’t. The request portion is the async action so will call and go keep going. At some point you’re going to have to wait for the returned result before moving on… I personally would do it inside the function to be cleaner but that’s just me.
I see… thanks. I have no idea how to do that, I have spent at least 2-3 hours trying to use async action but I was not able to implement it.
The article James linked to up above (Return request object undefined - #8 by James_Hibbard ) explains the approaches pretty well.
You can search for await in the article to go right to that section to look at how the pattern is applied.
Still stuck, someone? Thanks
Perhaps show your async await code attempt and someone can help guide you from there?
1 Like
Thanks, I managed to make it work.
Ok, cool. Do you fancy sharing the code you ended up with?
Sure.
const request = require('request')
const OAuth = require('oauth-1.0a')
const crypto = require('crypto')
let auth;
function generateToken() {
return new Promise((resolve, reject) => {
const oauth = OAuth({
consumer: {
key: 'xxx', //Access key
secret: 'xx-xxx',
},
signature_method: 'HMAC-SHA256',
hash_function(base_string, key) {
return crypto
.createHmac('sha256', key)
.update(base_string)
.digest('base64')
},
});
const request_data = {
url: 'https://account.api.here.com/oauth2/token',
method: 'POST',
data: { grant_type: 'client_credentials' },
};
request(
{
url: request_data.url,
method: request_data.method,
form: request_data.data,
headers: oauth.toHeader(oauth.authorize(request_data)),
},
function (error, response, body) {
if (response.statusCode == 200) {
result = JSON.parse(response.body);
auth = result;
resolve();
}
else {
reject('Error: Something went wrong!');
}
}
);
})
};
async function init(){
await generateToken();
}
await init();
// use auth object
console.log(auth);
Thanks to everyone. Appreciate any feedback if there’s something to improve.
You could tidy it up a little.
In the following examples, I’m resolving a promise after 1 second to simulate the network request.
let auth;
function generateToken() {
auth = crypto.randomUUID();
return new Promise(resolve => setTimeout(resolve, 1000));
};
generateToken()
.then(() => { console.log(auth); });
Or using async...await
:
let auth;
async function generateToken() {
auth = crypto.randomUUID();
await new Promise(resolve => setTimeout(resolve, 1000));
};
generateToken()
.then(() => { console.log(auth); });
I’m not the biggest fan of the auth
global (depending on what ís happening in the rest of the code).
You could get rid of it like so:
async function generateToken() {
await new Promise(resolve => setTimeout(resolve, 1000));
return crypto.randomUUID();
};
generateToken()
.then((auth) => { console.log(auth); });
Or if you need to assign the return value to a variable in the top scope of your script:
(async () => {
async function generateToken() {
await new Promise(resolve => setTimeout(resolve, 1000));
return crypto.randomUUID();
};
const auth = await generateToken();
console.log(auth);
})();
HTH
1 Like
system
Closed
April 29, 2022, 10:06pm
20
This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.