Currently,
I've made an axios common to calling API as:
export const API_LOCAL = axios.create({
baseURL: process.env.REACT_APP_BASEURL,
headers: {
'Authorization': `Bearer ${localStorage.getItem('token')}`,
'Accept': 'application/json',
'Content-Type': 'application/json',
},
timeout: 30000,
});
First time when I start to import and use file with this export as API_LOCAL, I'm not use the 'Authorization', the localStorage.getItem('token') is null. Then I'll get some data and set back to localStorage.setItem('token','SOME_SAMPLE_TEXT').
After that, when in another calling which use API_LOCAL, I think it's cached because the API_LOCAL with localStorage.getItem('token') is always null.
Could I set up for the dynamic reload import file to get latest data?
Thank you for any guides.
the best way to handle Bearer token is via interceptor.
You can do something like
axios.interceptors.request.use((config) => {
const token = localStorage.getItem('token');
if ( token != null ) {
config.headers.Authorization = `Bearer ${token}`;
}
}
This way every axios request will be sent with your auth token
Related
I am new to using Axios configuration. **So I am wondering if it is possible to set axios header dynamically?**
Because the end points I am calling right now need a Authentication and different authentication for different api, so I want make a change to the created axios instance’s header when token is expired and with different URL.
Here is my current code:
in config.js
import axios from 'axios'
// to get Authorization for api_1
const {access_token_1} = axios.get('url/access_token_1')
// to get Authorization for api_2
const {access_token_2} = axios.get('url/access_token_2')
export const instance = axios.create({
headers: { Authorization: `Bearer ${access_token_1}` },
})
My Api_1 and 2 call
//Api_1
export const getCountry = async (country: string) => {
const response = await instance.get(
`/sas/${country}`
)
return response.data
}
//Api_2
export const getCity = async (city: string) => {
const response = await instance.get(
`/sps/${city}`
)
return response.data
}
I know header can be set again by certain method, but how could I set it again only when it’s expired and set the instance with right authentication for certain Api
Have a look at this documentation, you can create/update headers and pass them to your axios instance. I think this examples might help a little
axios.defaults.baseURL = 'https://api.example.com';
// Important: If axios is used with multiple domains, the AUTH_TOKEN will be sent to all of them.
// See below for an example using Custom instance defaults instead.
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
const options = {
method: 'POST',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
data: qs.stringify(data),
url,
};
axios(options);
axios.get('https://example.com/getSomething', {
headers: {
Authorization: 'Bearer ' + token //the token is a variable which holds the token
}
})
I am new to snipcart and I can’t connect to your APi, i work with Next.js and can’t find anything on the forum or the docs releated to my problem. When I make my call with getServerSideProps i get this unhandledRejectionRequest failed with status code 404. It’s seems that’s I am not authorized to connect however i put my secret API key like in the docs.
here my code:
const secret = Buffer.from(process.env.SNIPCART_API_ID).toString('base64');
const url = 'https://api.snipcart.com/api/products';
const config = {
headers: {
'Content-Type': 'application/json',
Authorization: `Basic${secret}`,
},
};
axios.get(url, config).then((result) => {
console.log(result);
}); ```
Help is welcome :grinning:
Thanks.
From the API Docs:
const secret = "YOUR_SECRET_API_KEY"
const request = await fetch('https://app.snipcart.com/api/orders', {
headers: {
'Authorization': `Basic ${btoa(secret)}`,
'Accept': 'application/json'
}
})
const result = await request.json()
So what I see are two things:
header NOT "content-type" but "Accept"
Missing space in Authorization Header. Not sure if this is relevant for template strings.
axios and axiosInstance behave differently when we exclude the Content-Type from header and send image. axios defaults to "multipart/form-data" as expected but axiosinstance goes for "application/x-www-form-urlencoded"
I want to send image from axios to backend. The Content-Type should be something like
The Content-Type is multipart/form-data + boundary calculated dynamically. My backend works fine when uploaded from postman. Setting Content-Type to only 'multipart/form-data' (without mentioning boundary) or adding custom boundaries doesn't seem to work.
On some research i learnt that axios will automatically set boundaries if we exclude the Content-Type from header. It seems to be true with axios but not with axiosInstance.
Please refer to the screenshots below
I have setup an axiosInstance which has interceptors attached to manage JWT authentication tokens.
import axios from 'axios';
import { BACKEND_URL } from './config';
import { store } from './redux/store';
import { setLoginFalse } from './redux';
const baseURL = BACKEND_URL;
const axiosInstance = axios.create({
baseURL: baseURL,
timeout: 360000,
transformRequest: [
function (data, headers) {
const accessToken = window.localStorage.getItem('access_token');
if (accessToken) {
headers['Authorization'] = `Bearer ${accessToken}`;
} else {
delete headers.Authorization;
}
return JSON.stringify(data);
},
],
headers: {
'Content-Type': 'application/json',
accept: 'application/json',
},
});
// handling the expiry of access tokens through response interceptors
axiosInstance.interceptors.response.use(
// code for managing JWT tokens
);
export default axiosInstance;
First i will send it using axios (not axiosInstance the i just defined)
let formData = new FormData();
formData.append('profile_pic', file, file.name);
axios
.put('/users/profile-pic-upload/', formData)
.then((res) => console.log(res))
.catch((err) => console.log(err));
I am printing the Content-Tyoe in server side. We can see that it set the type correctly.
[!Server side printing Content-Type for axios]3
But when i use axiosInstance for same (i don't specify Content-Type in both cases and let axios pick it).
let formData = new FormData();
formData.append('profile_pic', file, file.name);
axiosInstance
.put('/users/profile-pic-upload/', formData)
.then((res) => console.log(res))
.catch((err) => console.log(err));
In this case axiosInstance picked "www-form-urlencoded" differeing from axios which picked "multipart/fform-data" with correct boundaries.
I cannot set Content-Type: "multipart/form-data" it won't work without boundary. Also copying the same boundary as sent by Postman (for same image) from axios doesn't seem to work.
I somehow need to tell axiosInstance to default to 'multipart/form-data' without setting the Content-Type (becuase boundaries need to be calculated dynamically)
I have to use axiosInstance, i cannot use fetch or just axios because i have an interceptor bound to axiosInstance which handles refresh tokens.
Please suggest any fix for this.
Any help would be highly appreciated. Thank you.
I have one api.js which exports by default an axios.create() instance:
import axios from 'axios'
import Cookies from 'js-cookie'
const api = axios.create({
baseURL: process.env.VUE_APP_API_URL,
timeout: 10000,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${Cookies.get('Token')}`,
Organization: Cookies.get('Organization'),
Company: Cookies.get('Company')
}
})
export default api
Then I import this in multiple files like this:
//api/users.js
import api from './api.js'
const methods = {
postUser (params) {
return api.post('/users', params)
},
getUser (id) {
return api.get('/users/' + id)
}
}
export default methods
However there will be some functions that should update the Cookies Organization and Company and I was wondering if is possible to update the default api instance and automatically update it in all imports that use it. I know a simple page refresh would work but I'm building a SPA and I would like to prevent screen to be manually refreshed.
You can add the headers dynamically, that way the cookies will be read on every request.
import axios from 'axios'
import Cookies from 'js-cookie'
const api = axios.create({
baseURL: process.env.VUE_APP_API_URL,
timeout: 10000,
// Static headers
headers: {
'Content-Type': 'application/json',
},
transformRequest: [function (data, headers) {
// You may modify the headers object here
headers['Authorization'] = `Bearer ${Cookies.get('Token')}`
headers['Organization'] = Cookies.get('Organization')
headers['Company'] = Cookies.get('Company')
// Do not change data
return data;
}],
})
export default api
I would suggest to read about interceptor for axios. (https://github.com/axios/axios#interceptors)
A very basic example would be the following.
Lets assume your webservice would return a response http status 401 header.
You'd intercept the response with the following:
// Add a response interceptor
axios.interceptors.response.use(function (response) {
// happy case its 2XX
return response;
}, async (error) => {
if (error.response.status === 401) {
// do some logic to retrieve a new JWT or Cookie.get()
const jwt = Cookies.get('Token');
const config = error.config;
config.headers['Authorization'] = `Bearer ${jwt}`;
}
return await axios.request(config);
});
The next request will then have an authorization header attached to the request header.
In my application I need to GET some data (for which I provide the native authtoken).
In the same event, however, I also need to POST a second token to be consumed by a few endpoints, for external backend api calls.
How do I POST this second token using my working code below using axios?
Should I extend Authorization bearer or simply POST Spotify Token as string data?
How so?
My code:
getData(event) {
const {token} = this.props.spotifyToken
const options = {
url: `${process.env.REACT_APP_WEB_SERVICE_URL}/endpoint`,
method: 'get',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${window.localStorage.authToken}`
}
};
return axios(options)
.then((res) => {
console.log(res.data.data)
})
.catch((error) => { console.log(error); });
};
For an async await applied to your code would look something like this.
async getData(event) {
const {token} = this.props.spotifyToken
let getRes = await axios.get(`${process.env.URL}/endpoint` {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${window.localStorage.authToken}`
}
}
let postRes = await axios.post(`${process.env.URL}/endpoint` {
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${window.localStorage.authToken}`
}
}
console.log(getRes.data.data);
console.log(postRes.data.data);
};
In this specific case, where a token is needed to fetch data at backend, I found that passing token at url is more suitable, like so:
#endpoint.route('/endpoint/<select>/<user_id>/<token>', methods=['GET'])
def endpoint(name, user_id, token):
# business logic
and:
const options = {
url: `${process.env.REACT_APP_WEB_SERVICE_URL}/endpoint/${select}/${userId}/${this.props.spotifyToken}`,
method: 'get',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${window.localStorage.authToken}`
}
};
otherwise, backend code would run twice, for POST and GET, which is not desired in my case.