Jrow
Jrow

Reputation: 1054

Wait for API call return before proceeding

I am very weak in javascript but I think I understand what's going wrong. Just not fluent enough to know how to fix it or even how to correctly write it. I have a VueJS app that sends requests to an API with an access_token. When that access_token expiries it sends a refresh_token to the API and gets a new access_token. I want it to then redo the request it was running when it expired. Using the code below I get strange behavior. When it hits the 401 I can see it access the /token endpoint and get a new access_token however the next call to /brewery is using the old access_token. This happens about 5 times before a call to /brewery finally uses the new access_token and the loop stops. My guess is that when I call this.loaded() the call to auth.refreshToken() hasn't finished yet?

loaded(access_token){
        var headers;
        if(access_token)
        {
            headers = { 'Authorization': 'Bearer ' + access_token }
        }
        else
        {
            headers = auth.getAuthHeader();
        }
        axios.get(this.getBaseUrl + '/brewery/', { headers })
             .then((response) => {
                this.breweries = response.data.data.slice(0);                    
             })
             .catch((error) => {                    
                if(error.response.status == 401)
                {
                    console.log("error 401");
                    var new_access_token = auth.refreshToken();
                    this.loaded(new_access_token);
                }
            });
    }

Auth class

refreshToken(context) {
var token = 
{
  refresh_token: localStorage.getItem('refresh_token'),
  grant_type: 'refresh_token'
};
token = querystring.stringify(token);
axios.post(LOGIN_URL, token)
  .then((response) => {
    localStorage.removeItem('access_token');
    localStorage.setItem('access_token', response.data.access_token);
    this.checkLoggedIn();
    if(!this.isAdmin())
    {
      context.error = "You are not an admin user";
    }
    return response.data.access_token;
  })
  .catch(function (error) {
    if(error.response){
      if(error.response.status == 400)
      {
        console.log(error.response.data);
        context.error = error.response.data;
      }
    }
  })

}

Upvotes: 0

Views: 854

Answers (1)

lrcrb
lrcrb

Reputation: 910

This looks like promise chaining/structure issue. To make the call to this.loaded occur after the call to auth.refreshToken has completed you should make the refreshToken method return a promise. Specifically, it should return the axios.post call. That axios.post call, when successful is actually executing this line return response.data.access_token; and resolving the token. Now when you make a call to auth.refreshToken you should append a then block like so:

auth.refreshToken().then((token) => { this.loaded(token) })

Without structuring this code in a synchronous manner, you're going to get multiple calls to this.loaded because each one will fail with a stale token... or at the least an undefined token.

Upvotes: 1

Related Questions