I want to declare 2 axios instance,so 1 is for API call using access_token,another 1 is using refresh_token.
So I have a code like this:
config.js
import axios from 'axios';
const axiosAccessClient =function () {
const defaultOptions = {
baseURL: 'my_url',
headers: {
'Content-Type': 'application/json',
}
};
let instance = axios.create(defaultOptions);
instance.interceptors.request.use(function (config) {
const token = localStorage.getItem('access_token');
config.headers.Authorization = token ? `Bearer ${token}` : '';
return config;
});
return instance;
};
const axiosRefreshClient =function () {
const defaultOptions = {
baseURL: 'my_url',
headers: {
'Content-Type': 'application/json',
}
};
let instance = axios.create(defaultOptions);
instance.interceptors.request.use(function (config) {
const token = localStorage.getItem('refresh_token');
config.headers.Authorization = token ? `Bearer ${token}` : '';
return config;
});
return instance;
};
export {
axiosAccessClient,
axiosRefreshClient
}
So in my Request.js I do something like this:
import {axiosAccessClient,axiosRefreshClient} from "./config";
static async access(url,body) {
return await axiosAccessClient.post(url, body)
.then(function (response) {
return response;
}).catch(function (error) {
throw error;
})
}
static async refresh(url,body){
return await axiosRefreshClient.post(url, body)
.then(function (response) {
return response;
}).catch(function (error) {
throw error;
})
}
but when I run the app,it crash at the point of access() in Request.js show this error:
_AxiosConfig__WEBPACK_IMPORTED_MODULE_2__.axiosAccessClient.post is not a function
But if I do the following:
export default axiosAccessClient() in config.js,
import axiosAccessClient from "./config" in Request.js
then the code work(which is weird),but by this I cant access axiosRefreshClient from refresh() in Request.js
Question:
Can somebody tell me why is this happen? I read all this example,but still cant figure it out:
this question
this question and so on
How can solve this?? Export multiple function from a single file
Your config.js exports functions; you need to rewrite it so it exports the result of the function calls instead, i.e. the instances.
// change name of functions
function generateAccessClient() {
..
}
// create instances
const axiosAccessClient = generateAccessClient();
const axiosRefreshClient = generateRefreshClient();
// export them
export {
axiosAccessClient,
axiosRefreshClient
}
This way you can import both. Having a default export is unrelated to your problem, you just accidentally solved it by adding the () at the end.
Another way is to do this:
const axiosAccessClient = (function () {
...
})();
Same for axiosRefreshClient.
Now your original code will work.
Your two functions (axiosAccessClient and the other) return an axios instance, but the function itself is not an axios instance (that's why you can't call .post() on it). You should create the two clients in the same module and save them as const variables, and then export the instances (instead of functions that create instances). It makes no sense to re-create the same instance every time you wish to make a request. The parameters of the instance do not change, so saving the instance is better.
Related
In my code base there are various Axios instances created using
axios.create()
because there are multiple base URLs used in my app. So per baseURL we have created a corresponding Axios instance.
Now in App.js file, I have included 2 interceptors
request interceptor
response interceptor
axios.interceptors.response.use(
config => {
return config;
},
error => {
if (error && error.response.status === 401) {
signOut();
}
return Promise.reject(error);
}
);
But all the API calls are by-passing the above-mentioned 2 interceptors.
Problem:
I want to use the above-mentioned interceptors as the Global interceptors for all the Axios instances in my project.
First Option - "Easier"
Just create your own "axios generator" function.
const createAxios = (baseURL) => {
const newInstance = axios.create({ baseURL });
newInstance.interceptors.response.use(
(config) => config,
(error) => {
if (error && error.response.status === 401) {
signOut();
}
return Promise.reject(error);
}
);
return newInstance;
}
Second Option - More Complicated
Personally I prefer this option, as I find it more tidy, and logically separated and divided (each "entity" stands by itself).
What i would probably do is create a BasicService Class which would look something like this:
import axios from 'axios';
class BasicService {
constructor(url) {
const options = {
baseURL: url,
// any options that you would want for all axios requests,
// like (proxy, etc...)
};
this.fetcher = axios.create(options);
// Your default config
this.fetcher.interceptors.response.use(
(config) => {
return config;
},
(error) => {
if (error && error.response.status === 401) {
signOut();
}
return Promise.reject(error);
}
);
}
}
then for each axios instance i would like to create, i would also create a class with all fetches. like:
const baseURL= '/users';
class UserService extends Service {
// GET Requests
async GetAll() {
return (await this.fetcher.get('/all')).data;
}
// POST Requests
async insertUser(userToInsert) {
return await this.fetcher.post(...)
}
}
const userService = new UserService(baseURL);
export default userService;
then in any file i would just import my wanted service and fetch it
import UserService from "/services/UserService";
UserService.getAll().then(...);
This helps you keep the same config for all axios instances while keeping your code as generic and clean as possible
Good evening everyone, here I have a problem with my interceptor in VueJS. I don't understand where my problem comes from, and I'm pulling my hair out...
I've watched several tutorials, I've watched several topics on stackoverflow, but I don't understand what's going on at all.
When I put a debugger on, it's triggered, but when I switch to "axios.interceptors" it tells me that axios is undefined, it's incomprehensible...
import axios from 'axios';
debugger;
axios.interceptors.response.use(function (response) {
console.log(response);
// Any status code that lie within the range of 2xx cause this function to trigger
// Do something with response data
return response;
}, function (error) {
console.log(error);
// Any status codes that falls outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
});
const token = localStorage.getItem('token');
export default axios.create({
baseURL: process.env.VUE_APP_URL_API,
headers: {
Authorization: `Bearer ${token}`
}
})
The code above is called in my VueX Store.
import Http from "../../api/http";
export default {
state: {
customers: {},
customer: {},
},
getters: {
customers: state => state.customers,
},
mutations: {
SET_CUSTOMERS(state, customers) {
state.customers = customers;
}
},
actions: {
loadCustomers({commit}) {
Http.get('/customers').then(result => {
commit('SET_CUSTOMERS', result.data.data );
}).catch(error => {
throw new Error(`API ${error}`);
});
}
}
};
I want to trigger http code 401 to logout my user and destroy the token in the browser.
If anyone could help me, I would be delighted, thank you very much.
Regards,
Christophe
As shown in the interceptor docs, just below the example interceptors, if you use an instance, you have to add the interceptor to it:
import axios from 'axios';
const token = localStorage.getItem('token');
const instance = axios.create({
baseURL: process.env.VUE_APP_URL_API,
headers: {
Authorization: `Bearer ${token}`
}
})
instance.interceptors.response.use(function (response) {
console.log(response);
// Any status code within the range of 2xx cause this function to trigger
// Do something with response data
return response;
}, function (error) {
console.log(error);
// Any status codes outside the range of 2xx cause this function to trigger
// Do something with response error
return Promise.reject(error);
});
export default instance;
For people which are wondering how the issue has been solved, there is my code :)
success.js
export default function (response) {
return response
}
failure.js
import router from 'vue-router'
export default function (error) {
switch (error.response.status) {
case 401:
localStorage.removeItem('jwt.token')
router.push({
name: 'Login'
})
break
}
return Promise.reject(error)
}
adding this to main.js
const token = localStorage.getItem('jwt.token')
if (token) {
axios.defaults.headers.common.Authorization = token
}
create api.js which is my client for all the request, so my request are always passing by this.
import axios from 'axios'
import success from '#/interceptors/response/success'
import failure from '#/interceptors/response/failure'
const api = axios.create({
baseURL: process.env.VUE_APP_URL_API
})
api.interceptors.request.use((config) => {
const token = localStorage.getItem('jwt.token')
config.headers.Authorization = `Bearer ${token}`
return config
})
api.interceptors.response.use(success, failure)
export default api
I hope it will be usefull :)
Im very new with Axios, and im trying to do a POST request using Axios and my DB is not getting the data, it creates one entity and all the values are null except the primary key that is 0. Then, i get an error that i'm duplicating the primary key. I don't know if its not getting my JSON or if im doing something else wrong.
api.js
import axios from "axios";
const endpoints = {
development: 'http://localhost:8080/',
};
export const api = axios.create({
baseURL: endpoints['development'],
timeout: 20000,
headers: {"Content-type":"application/json" }
});
pacienteService.js
import { api } from './helpers/api.js';
const basePath = 'api';
let config = {
headers: {
'Content-Type': 'application/json',
}
}
function getAll() { return api.get(`${basePath}/pacientes`); }
function show(pacienteId) { return api.get(`${basePath}/?id=${pacienteId}`); }
function create(data) { return api.post(`${basePath}/pacientes`, data,config); }
const pacientesService = { getAll, show, create };
export default pacientesService;
Function that do the post when Submitting the form
handleSubmit(event){
const paciente = {rut:this.state.rut,
nombre:this.state.nombre ,
nacionalidad:this.state.nombre ,
sexo:this.state.nombre ,
fecha_na:this.state.nombre ,
domicilio:this.state.nombre ,
diagnostico:this.state.nombre ,
telefono:this.state.nombre ,
gravedad:this.state.recuperacion
}
pacientesService.create({paciente}).then(res => {
console.log(res);
console.log(res.data);
})
}
Pd: I have printed all the states to see if they're correct, and they are.
Fixed it passing data directly to pacientesService.create().
From pacientesService.create({paciente}), to
pacientesService.create({rut:this.state.rut,nombre:this.state.nombre,... })
I have a problem on using the axios interceptor in my react app. I want to achieve putting the header token just once in my react app. So thats why Im putting it in the interceptor. At the same time, i also want to have just one declaration to get the error. So i dont need to show the error in every page. I’m wondering if i’m using it correctly in my code below? Is there a way that i can shorten it cause i’m declaring it twice for response and request?
export function getAxiosInstance() {
if (axiosInstance === null) {
axiosInstance = axios.create({
baseURL: API_URL,
});
}
axiosInstance.interceptors.request.use(
(config) => {
if (config.baseURL === API_URL && !config.headers.Authorization) {
const token = store.getState().auth.access_token;
if (token) {
config.headers.Authorization = `Bearer ${token}`;
console.log(config);
}
}
return config;
},
(error) => {
console.log(error);
store.dispatch(setAPIErrorMessage(error.message));
return Promise.reject(error);
}
);
axiosInstance.interceptors.response.use(
(config) => {
if (config.baseURL === API_URL && !config.headers.Authorization) {
const token = store.getState().auth.access_token;
if (token) {
config.headers.Authorization = `Bearer ${token}`;
console.log(config);
}
}
return config;
},
(error) => {
console.log(error);
store.dispatch(setAPIErrorMessage(error.message));
return Promise.reject(error);
}
);
return axiosInstance;
}
You don't need to set authorization header in interceptors.response, you only need this in request interceptor.
You could declare your error handling in a closure function (with the action dispatch) to avoid repeating yourself.
I would also suggest to avoid handling errors directly in axios instance. You could define async redux actions using https://github.com/reduxjs/redux-thunk, and handle network errors at redux level (using fetchBegin, fetchSuccess, fetchFailure actions pattern). Then axios setup and redux setup would not be coupled anymore, which will allow you to change these tools in the future.
I'm attempting to display data with axios, promises, and other ES6 features. This project works in prod, but after changing the API endpoints around in dev (no longer working w/ old endpoints) I've run into issues.
For some reason, the variable I'm working with (kkUser) is coming up as undefined. I'm not sure if it has to do with the different endpoints or something else.
Helper file:
const kkObj = {};
export async function loadKKProperties(obj) {
kkObj.spUrl = _spPageContextInfo.siteAbsoluteUrl;
kkObj._KKRestHost = "https://ha----dev.com";
kkObj._BaseHost = "https://in-url.com";
// other code
JS:
import { loadKKProperties } from "./helperfile";
import axios from "axios";
function getDocFolders(kkUser, places) {
return kkUser
.userValidatedPostRequest({
// stuff
}
})
// more code
async function globalInitPromise() {
const kkObj = await loadKKProperties();
const token = await permissionToCallKKAPI(kkObj.hsHost);
const kkUser = new KKUser(kkObj, token);
class KKUser {
constructor(kkObj, token) {
this.kkObj = kkObj;
this.token = token;
}
// other code
userValidatedPostRequest(dataObj) {
dataObj.Params.SAMAcct = this.kkObj.currentAccount;
return axios
.post(this.kkObj._KKRestHost + "/myAPI/api/Query/Post", dataObj, { // debugger gets stuck here
"query": {
"__metadata":{"type":"SP.CamlQuery"}
},
withCredentials: true,
headers: {
Accept: "application/json;odata=verbose",
Authorization: this.token,
"X-RequestDigest": $("#__REQUESTDIGEST").val()
}
})
// .then
// .catch
Console:
404 error