0

I have an Express.js / Node.js API project where I am calling a endpoint that depends on an internal async function.

const express = require('express');
const fetch = require('node-fetch');
const router = express.Router();
module.exports = router;

async function getToken() {
  fetch("www.example.com", {
    method: "post",
    headers: {
      "Authorization": "Basic " + btoa(userName + ':' + password),
      "Accept": "application/json"
    }
  })
    .then(response => response.json())
    .then(json => {
      console.log(json)
      return { response_code: 200, response: json }
    })
    .catch(err => {
      return { response_code: 500 }
    })
}

router.get('/getAll', async (req, res) => {
  var token = await getToken()
  console.log(token)
  res.status(200).json({'response': token})
})

What I want here is that function getToken() should be able to be called from multiple endpoints. For example, when /getAll endpoint is called, it gets the token from getToken() first and then proceeds with its own logic. For this I am using await keyword.

But when I call the /getAll endpoint, I get undefined in the return value of await getToken(). I have checked using console.log() and I can see that the console in /getAll gets called first, and after that I get the actual token value that is being logged from inside async function getToken().

Why is this happening and what can I change to get the token value from my function?

Uzair A.
  • 1,586
  • 2
  • 14
  • 30
  • There's no point making a function async if it doesn't await anything. Right now getToken returns a promise of undefined _totally unconnected_ from the fetch promise. – jonrsharpe Feb 25 '23 at 09:44
  • you are returning a value in your `getToken()` function, you need to return the result of a promise – balexandre Feb 25 '23 at 09:44

1 Answers1

1

in your code, you have a plain function, meaning that it ends the function and gets out, as it awaits for nothing and returns nothing... as you are returning only inside something that will occur later in time (after the fetch is done, it could be after 0.0001s or 10s, you don't know)

async function getToken() {
  fetch("www.example.com", {
    method: "post",
    headers: {
      "Authorization": "Basic " + btoa(userName + ':' + password),
      "Accept": "application/json"
    }
  })
    .then(response => response.json())
    .then(json => {
      return { response_code: 200, response: json }
    })
    .catch(err => {
      return { response_code: 500 }
    })

    // returns right here, always...
}

to make it working you need to tell the function that you are returning a result, for example

function getToken() {
  return fetch("www.example.com", { // we're asking the function to return it's result
    method: "post",
    headers: {
      "Authorization": "Basic " + btoa(userName + ':' + password),
      "Accept": "application/json"
    }
  })
    .then(response => response.json())
    .then(json => {
      return { response_code: 200, response: json }
    })
    .catch(err => {
      return { response_code: 500 }
    })
}

Important note when using fetch()

one thing you should be aware is that you're catch is in the wrong place, as you are calling .then(response => response.json()) and the function could have thrown before this call, and you would have no response at all

here's a nice video of what is happening and how you can improve it https://twitter.com/Steve8708/status/1611437686958739456?lang=en


a simple live working example

function getToken() {
  return fetch("https://holidays.coding.garden", {
    method: "get",
    headers: {
      "Accept": "application/json"
    }
  })
    .then(response => response.json())
    .then(json => {
      return { response_code: 200 }
    })
    .catch(err => {
      return { response_code: 500 }
    })
}

(async () => {

    console.time('fetch')

    console.log('here 1')
    const result = await getToken()
    console.log('here 2', result)

    console.timeEnd('fetch')
    
})()
balexandre
  • 73,608
  • 45
  • 233
  • 342