3

I have some code that authenticates by posting an object using npm request.

After posting the JSON object, a JSON response is returned which contains an authn token I can use in future GET/POST request headers.

I have some async code that returns the correct authn token but I can only access it via the .then function code block.

I have read through the usual linked thread here: How do I return the response from an asynchronous call? but even though the return result is in the .then function I still get undefined when trying to do anything other than console.log().


const postData = {
  "auth": {
    "username": "username",
    "password":"password"
  }
};

var returnRequest = () => {
  var options = {
    method: 'POST',
    url: 'https://api.appnexus.com/auth',
    body: postData,
    json: true
  };

  return new Promise(async (resolve, reject) => {
    await requestAPI(options, function (error, response, body) {
      if (error) {
        reject(error);
      }
      resolve(body);
    });
  })
}

var returnedResult

returnRequest()
  .then((result) => {
     returnedResult = result.response.token
  })
  .catch((error) => {
    console.log(error);
  })

  console.log(returnedResult)

I would expect to see the returnedResult store the token as I understand it, the .then promise only runs one the request has happened?

A developer said I have to build all subsequent code inside the .then block but that sounds crazy, that I have to have my whole program inside this returnRequest function rather than be able to pass the returned token back outside to a global variable?

Is that the correct way to do it, and am I supposed to just build all subsequent requests using the result.response.token inside the

returnRequest()
  .then((result) => {
     returnedResult = result.response.token
  }) 

function?

  • Yes, anything that needs the resolved value goes inside the `then`. You seem to have async/await, so you have the option of using that instead to do the equivalent without nesting. Note that `new Promise(async …)` is always wrong – just remove the `async` and `await` there. – Ry- Nov 03 '19 at 02:35

4 Answers4

4

.then is the mechanism that promises use to let you know when the value is available. The "when" part is important: only the promise object knows what time your code should run at. So even if you try to write some extra code to store values in variables, the question of when it's safe to try to get those variables can only be answered by the promise's .then method.

So yes, any code that needs the values to be available needs to be put in the .then of the promise. Maybe you have some separate part of the codebase that needs to interact with the result, and so it feels clumsy to try to have to copy that code over to here. Well you don't need to: you just need to pass that other code the promise, and then that other code can call .then on the promise itself. For example:

const tokenPromise = returnRequest()
  .then(result => result.response.token);

// Anywhere else that tokenPromise in scope can write whatever code it needs to:
tokenPromise.then(token => {
  // Do anything with the token
});

// And a completely different piece of code can write its own stuff with the token
tokenPromise.then(token => {
  // Do other stuff with the token
});
Nicholas Tower
  • 72,740
  • 7
  • 86
  • 98
1

No you don't need to use result.response.token everywhere to use the authn token. The thing here to understand is the flow of code. Your console.log statement may be returning you undefined .

Why ? Haven't you updated the global variable inside the then block of promise ?

Yes you have ! But the problem is that it is not reflected to you in the console log statement because this very statement is executed before any updation in the global variable.
So, it gets updated but it takes time to do so. This is what is known as asynchronous code .

Now what about the suggestion of wrapping the code inside the .then block.

If you will add a console log statement beneath the updation (inside the then block) it will print you the exact token you are looking for.

But actually you don't need that , you can use aysnc/ await syntax to make it look like synchronus code, and then it will don't confuse you.

For example you can do something like this.

 let  result = await  returnRequest(); 
 let returnedToken =result.response.token;
  // Now it will print you the token
 console.log(returnedToken)

Make sure to add the async keyword infront of the function using await.

Mukul Kumar Jha
  • 1,062
  • 7
  • 19
0

there are several ways to do what you ask, one way would be to wrap your entire code in async iife (immediately invoked function expression) so that you can use await.

!async function(){
  ....
  ....
  ....
  var  returnedResult = await returnRequest()
    .then((result) => {
      return result.response.token;
    })
    .catch((error) => {
      console.log(error);
    })
  //continue
}()
ibrahim tanyalcin
  • 5,643
  • 3
  • 16
  • 22
0

I’ll try and answer parts of this question.

  1. The setting of value for global variable inside of the .then callback is correct and you’ll have the value inside the “then” block. You can console.log inside of it and check.

  2. The console.log outside in the “global” scope runs even before the the promise is resolved. Remember that java script is even driven. It registers the api call and continues executing the next line of it can. Which is why you’ll see an undefined value of token.

  3. If all your subsequent requests depend on the auth token and you need to call some other API in the same call, you’ll have to do it in the .then call or create a promise chain with multiple .then which is essentially the main benefit of Promises. Previous result is passed on to the next promise.

Gautam
  • 108
  • 8