0

I want to connect to an external api using some node-fetch code. My code first sends the login details & should receive a token from the api. Then this token is used for all the later communications.

Here is the code :

import fetch from 'node-fetch';
function getTokenForAuth(info) {
    try {
        var auth_token = '';
        fetch(api_url + '/api/api-token/', {
            method: 'POST',
            body: JSON.stringify(info),

            headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json'
            }
        })
        .then(function(res) {
            return res.json();
        })
        .then(function(json) {
            auth_token = json;
        })
        return auth_token.token;
    }

    catch (e) {
        console.log('[-] Error: Token Not Received');
        console.log('[!] Exception: ' + e);
    }
}

function getJSONFromRelativeURL(relativeURL, info) {
    return fetch(`${api_url}${relativeURL}`, {
        method: 'GET',
        headers: {
            'Content-Type': 'application/json',
            'Authorization': 'Token ' + getTokenForAuth(info)
        }
    })
    .then(function(res) {
        console.log(res);
        return res.json();
    })
    .then(function(json) {
        console.log(json);
    })
}

In the getJSONFromRelativeURL() function's request headers, if I hardcode the token, I get correct results. But if I run the code as it is now, I get an error saying : { detail: 'Invalid token.' }.

I think this is because of async nature of the promise in the fetch function, because of which it sometimes isnt able to send the token in time before the getJSONFromRelativeURL() gets called. I am not sure about this hypothesis & don't know how to correct this.

Kapil Gupta
  • 7,091
  • 5
  • 16
  • 25
  • `getTokenForAuth` returns a promise Object. So you are not setting Auuthorisation header. Try to console it and you will see an object instead of token. Must call `getTokenForAuth` and in it's `.then()` call the `getJSONFromRelativeURL` function. So that you will get the token as string. Also must return the token from inside the then and not outside. – Nidhin David Aug 05 '17 at 16:18
  • anyway I was the first one to answer. What made you not understand my answer so that I can improve? – Nidhin David Aug 06 '17 at 18:00
  • I just selected the other answer because its code was better put together and he also replied regarding my assumption (I wasn't sure about it). I think , looking back, that his answer is also put together in a better way with a logical flow (showing me what I did wrong and then answering step by step). – Kapil Gupta Aug 08 '17 at 14:38

2 Answers2

2

Your problem is here:

.then(function(json) {
    auth_token = json;
})
return auth_token.token;

Your return statement is outside the Promise chain. This means that, at the point you hit return, the fetch request hasn't had a chance to even run yet. You've essentially just told the fetch Promise chain what to do when it does return.

So essentially

I think this is because of async nature of the promise in the fetch function, because of which it sometimes isnt able to send the token in time before the getJSONFromRelativeURL() gets called.

is 100% correct.

What you'll need to do is restructure things a little bit:

function getTokenForAuth(info) {
  return fetch(api_url + "/api/api-token/", {
    method: "POST",
    body: JSON.stringify(info),

    headers: {
      "Content-Type": "application/json",
      Accept: "application/json"
    }
  }).then(function(res) {
    return res.json();
  });
}

function getJSONFromRelativeURL(relativeURL, info) {
  return getTokenForAuth(info)
    .then(function(token) {
      return fetch(`${api_url}${relativeURL}`, {
        method: "GET",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Token ${token}`
        }
      });
    })
    .then(function(res) {
      console.log(res);
      return res.json();
    })
    .then(function(json) {
      console.log(json);
    });
}
rossipedia
  • 56,800
  • 10
  • 90
  • 93
1

Have not tested it but it looks something like the following. For error handling use .catch(()=>{}) at the end of each chain.

   function getTokenForAuth(info) {

            var auth_token = '';
            return fetch(api_url + '/api/api-token/', {
                method: 'POST',
                body: JSON.stringify(info),

                headers: {
                    'Content-Type': 'application/json',
                    'Accept': 'application/json'
                }
            })
            .then(function(res) {
                return res.json();
            })
           }


    function getJSONFromRelativeURL(relativeURL, info, token) {
        return fetch(`${api_url}${relativeURL}`, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': 'Token ' + token
            }
        })
        .then(function(res) {
            console.log(res);
            return res.json();
        })
        .then(function(json) {
            console.log(json);
        })
    }


    getTokenForAuth(info)
    .then((token)=>{
      return getJSONFromRelativeURL(relativeURL, info, token)
    })
Nidhin David
  • 2,426
  • 3
  • 31
  • 45