Reputation: 3051
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:
Upvotes: 4
Views: 17169
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
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
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.
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')
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