medev21
medev21

Reputation: 3051

Axios - Interceptors not working on request error - 401 code

I have a simple react app that is using a third API to fetch data. Before making any requests, a token must be retrieved in order to use it in the headers. This token is created by using the same API by passing the client id and secret id - the API is Artsy API. This token has an expiration date so this API must be requested if the token doesn't not exist. After getting the token, then I can call other requests without a problem.

I have set up the API requests in a separate file, like so: Apis.js

import Axios from 'axios';
const baseURL = 'https://api.artsy.net/api';

// set up xap-token and set tot default headers
const instance = Axios.create({
    baseURL: baseURL + '/tokens/xapp_token',
    params: {
        'client_id': process.env.CLIENTID,
        'client_secret': process.env.CLIENTSECRET
    }
});

instance.interceptors.request.use(undefined, err => {
    const status = err.response ? err.response.status : null;
    console.log("auth",err.response)

    if(status === 401){
        console.log("auth",err.response)
        return 'hello'
        // this.getAuthToken();
    }
});

export default{

    getArtworks: function(){
        return new Promise((resolve, reject) => {
            instance.get(baseURL + '/artworks')
            .then(res => {
                resolve(res)
            })
            .catch(err => {
                reject(err);
            });
        });
    },

    getArtists: function(){
        return new Promise((resolve, reject) => {
            instance.get(baseURL + '/artists')
            .then(res => {
                resolve(res)
            })
            .catch(err => {
                reject(err);
            });
        });

    },

    getTest: function(){
        return 'hello';
    }
};

Not really sure how to use the create and interceptors, but I created an Axios instance. So the idea is to create some sort of middleware, create an instance and then use it as an interceptor if there is a request on that error. If there is, then apply the token to that instance and proceed with the request, retry. Also not sure how to set the the token in the instance.

So far I'm getting a 401 error in the getArtists method, this api gets called when the page loads, it's under componentDidMount.

App.jsx

import React, { Component } from 'react';
import Apis from './utils/Api';
import Gallery from './components/Gallery';

class App extends Component{
    constructor(props){
        super(props);
        this.state = {
            artWorks: []
        }
    }

    componentDidMount = () => {
        // Apis.getArtists();
        Apis.getArtists().then(res => {
            console.log(res)
            // this.setState({
            //     artWorks: res.data
            // })
        });
    }

    render(){
        return(
            <div>
                <Gallery artists={this.state.artWorks}/>
            </div>
        )
    }
}

export default App;

This is the api doc links for authentication.

Can anybody help? not really sure how to use the instance as a "middleware"? new to Axios. I would like to avoid 3rd library middleware, I prefer to learn in a manual way than using 3rd libraries. Your help will be much appreciated

Update:

I was able to get this somewhat working, i modified the instance.interceptor:

instance.interceptors.response.use(undefined, err => {
    const status = err.response ? err.response.status : null;
    if(status === 401){
        console.log("auth",err.response)

        instance.post(err.config.authURL, err.config.auth).then(res => {
            let token = res.data.token;
            err.config.headers['X-XAPP-Token'] = token;
            console.log('calling',err.response)
            return instance.request(err.config)
        });
    }

    // return Promise.reject(err);
});

But I'm getting undefined in the getArtists response. Not sure what's going on here. Here is a screenshot of the console:

enter image description here

Upvotes: 4

Views: 17169

Answers (3)

KARTHIKEYAN.A
KARTHIKEYAN.A

Reputation: 20148

I have initally faced same problem due interceptor not called until component get mounted. After that i have factured code now its working fine. see the code below how i did in correct way

httpConfig.js

import axios from 'axios'
import { baseURL } from '../utils/config'
import { SetupInterceptors } from './SetupInterceptors'


const http = axios.create({
    baseURL: baseURL
})

SetupInterceptors(http)

export default http

SetupInterceptors.js

import { baseURL } from '../utils/config'


export const SetupInterceptors = http => {

    http.interceptors.request.use(
        config => {
            config.headers['token'] = `${localStorage.getItem('token')}`
            config.headers['content-type'] = 'application/json'
            return config
        },
        error => {
            const status = error?.request?.status || 0
            const resBaseURL = error?.request?.config?.baseURL
            if (resBaseURL === baseURL && status === 401) {
               if (localStorage.getItem('token')) {
                  localStorage.clear()
                  window.location.assign('/')
                  return Promise.reject(error)
               } else {
                  return Promise.reject(error)
               }
            }
            return Promise.reject(error)
        }
    )

    http.interceptors.response.use(function(response) {
        return response
    }, function (error) {
        const status = error?.response?.status || 0
        const resBaseURL = error?.response?.config?.baseURL
        if (resBaseURL === baseURL && status === 401) {
            if (localStorage.getItem('token')) {
                localStorage.clear()
                window.location.assign('/')
                return Promise.reject(error)
            } else {
                return Promise.reject(error)
            }
        }
        return Promise.reject(error)
    })
}

export default SetupInterceptors

Upvotes: 0

Nagesha S
Nagesha S

Reputation: 83

Even I was facing same issue, it is resolved by using below code

export const instance = axios.create({ baseURL: API_BASE_URL })
    const instance = axios.create();
    instance.interceptors.response.use((response) => {
      console.log(`response ${response}`);
      return response;
    }, (error) => {
      console.log(`error ${error}`);
      return Promise.reject(error);
    });

instance.interceptors.request.use(
            (config) => {
                if (this.isUserLoggedIn()) {
                    localStorage.setItem(APP_TOKEN, token)
                    config.headers.Authorization = token
                }
                return config
            }
        )

Upvotes: 2

MinimalistYing
MinimalistYing

Reputation: 356

You should use instance.interceptors.response rather than instance.interceptors.request .

Because the request interceptor is called before Ajax request send. I think the response interceptor is actually what you want here.


  1. About BaseURL, you should set like below
const instance = Axios.create({
    baseURL: 'https://api.artsy.net/api'
})
// because you set the baseURL of the instance
// this will request url https://api.artsy.net/api/artworks
instance.get('/artworks')
  1. About 401 Error you get, from the api doc you give.I think you should request to get the token before your app start.
instance.post('tokens/xapp_token').then(res => {
  /* here is the response
{
  "type" : "xapp_token",
  "token" : "...",
  "expires_at" : "2014-09-05T12:39:09.200Z"
}
  */

  // you can set common request headers like this
  // or use request interceptors here to set headers
  // then every request you sent by instance after will have X-XAPP-Token header
  instance.defaults.headers.common['X-XAPP-Token'] = res.token
})

Actually err.config.headers['X-XAPP-Token'] = token; this code will not affect the request headers.

Upvotes: 9

Related Questions