react-native axios interceptor where to ubicate - react-native

i have a interceptor with axios but i don't know where to ubicate it. i attach javascript
import axios from 'axios';
import {getStoreData, checkStoreData} from './../utils/safestorage';
axios.interceptors.request.use(
async config => {
console.log('interceptor working');
const checkUser = await checkStoreData('user');
if (checkUser) {
const data = await getStoreData('user');
datajson = JSON.parse(data);
config.headers.Authorization = `Bearer ${datajson.access_token}`;
return config;
}
},
error => {
return Promise.reject(error);
},
);

I solved it importing the file in my app.js, an then my interceptors initialized.

Related

Cant use SecureStore in Service Middleware React Native App with Expo

Here is my code
import axios from "axios";
import AuthService from "./auth";
import * as SecureStore from "expo-secure-store";
const API_URL = "MYURL";
const instance = axios.create({
baseURL: API_URL,
token: await SecureStore.getItemAsync("token"),
timeout: 1000,
});
const ServiceMiddleware = {
post: async (url, data) => {
const res = await axios.post(API_URL + url, data);
return res.data;
},
get: async (url, req) => {
const res = await instance.get(url, { params: req });
return res.data;
},
put: async (url, data) => {
const res = await axios.put(API_URL + url, data);
return res.data;
},
delete: async (url) => {
const res = await axios.delete(API_URL + url);
return res.data;
},
};
export default ServiceMiddleware;
I would like to call Expo Secure Store in service middleware to get the token, but when I try to launch the application it gives me error.

How to call useNavigation inside axios file

I try to implement axios interceptor, for my request.
So when the error response is forbidden (401), I want to clear token and navigate to login screen.
But when I want to call useNavigation from react navigation v5 inside my axios file, it always shows error like this.
React Hook "useNavigation" is called in function "refreshAccessToken" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter.
This is my axios file code,
import axios from 'axios'
import AsyncStorage from '#react-native-community/async-storage'
import {useNavigation} from '#react-navigation/native'
import {generateRandomString, getDeviceInfo} from '../helper/helper'
const base = axios.create({
baseURL: '------',
timeout: 500000,
headers: {
'Content-Type': 'application/json'
}
})
async function refreshAccessToken() {
const navigation = useNavigation()
try {
const refreshToken = await AsyncStorage.getItem('refreshToken')
const response = await base.get('------', {
refreshToken
})
await AsyncStorage.setItem('accessToken', response.data.accessToken)
console.log('Response from refresh access token ', response)
return Promise.resolve(response.data)
} catch (error) {
console.log('Error from refresh access token', error.response)
if (error.response.data.errors.flag === 'INVALID_REFRESH_TOKEN') {
await AsyncStorage.removeItem('refreshToken')
await AsyncStorage.removeItem('accessToken')
}
return Promise.reject(error)
}
}
base.interceptors.request.use(
async function (config) {
const accessToken = await AsyncStorage.getItem('accessToken')
config.headers.authorization = accessToken
const deviceInfo = await getDeviceInfo()
const latitude = await AsyncStorage.getItem('latitude')
const longitude = await AsyncStorage.getItem('longitude')
config.headers['accept-language'] = 'id-ID'
config.headers['version'] = '1.0.0'
config.headers['date'] = new Date().toUTCString()
config.headers['x-coordinate'] = `${latitude};${longitude}`
config.headers['x-trace-id'] = generateRandomString()
config.headers['x-device'] = `${deviceInfo.deviceType}/${deviceInfo.deviceName}/${deviceInfo.deviceVersion}/${deviceInfo.deviceUid}`
return config
},
function (error) {
return Promise.reject(error)
}
)
base.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config
if (error.response.status === 403 && !originalRequest._retry) {
originalRequest._retry = true
const accessToken = await refreshAccessToken()
originalRequest.headers.Authorization = accessToken
return axios(originalRequest)
}
return Promise.reject(error)
}
)
export default base
You can't, hooks are only meant to be called inside components. There is a guide on how to navigate without the navigation prop you could use for this situation though.
You could also send an event (via a custom event emitter) and set up a listener anywhere else in your app where the navigation prop is available.

How to set authorization header coorectly?

Problem:
In my react native app in order to remove repeated calls I have developed a general POST GET methods in httpClient file. It code is look likes this.
import axios from 'axios';
import AsyncStorage from '#react-native-community/async-storage';
axios.defaults.headers.post['Content-Type'] = 'application/json';
var instance = null;
const setAuthorisationHeder = async () => {
const token = JSON.parse(await AsyncStorage.getItem('auth_data'));
if (token) {
console.log('>>>>>> instance', instance);
Object.assign(instance.headers, {
Authorization: 'Bearer' + token.accessToken,
});
} else {
console.log('>>>>>> instance', instance);
Object.assign(instance.headers, {
Authorization: '',
});
}
};
export const setHeader = () => {
console.log('>>>>>>>> HIIII');
instance = axios.create({
baseURL: '',
timeout: 150000,
headers: {
'Content-Type': 'application/json',
},
});
instance.interceptors.response.use(
function (response) {
return response;
},
async function (error) {
if (error.response.status) {
if (error.response.status === 401) {
AsyncStorage.removeItem('auth_data');
} else {
throw error;
}
} else {
console.log(error);
}
},
);
};
export const Get = (route, data) => {
function getData() {
return instance.get(
route,
data == null ? {data: {}} : {data: JSON.stringify(data)},
);
}
if (instance) {
console.log('>>>>>> HIIIIii');
// setAuthorisationHeder();
return getData();
}
return setHeader().then(getData);
};
export const Post = (route, data) => {
console.log('>>>>>> route', route);
function postData() {
return instance.post(route, JSON.stringify(data));
}
if (instance) {
console.log('>>>>>> HIIIIii');
// setAuthorisationHeder();
// setAuthorisationHeder();
return postData();
}
return setHeader().then(postData);
};
Can some tell me a way to add an authorization header to this instance? My token is storing the Asyncstorage in the middle of some actions so at the beginning called I don't have the token. As my code setHeader is running only one time so I created a method call setAuthorisationHeder() function. But it is giving me can not find property .then error when I am putting a request. Can someone help me to solve this issue? Thank you?
you can define global headers once and use it in every network call.
https://github.com/axios/axios#global-axios-defaults
Create a global auth variable where you'll store the auth data from storage. Before making a request get the auth data and use interceptor to set the bearer token.
let authToken = '';
const getAuthToken = async () => {
// asumming auth token was saved as string
authToken = await AsyncStorage.getItem('auth_data');
};
Interceptor
// request interceptor
axiosInstance.interceptors.request.use(
function (config) {
// Do something before request is sent
config.headers.Authorization = `Bearer ${authToken}`;
return config;
},
function (error) {
// Do something with request error
return Promise.reject(error);
}
);
complete code
import axios from 'axios';
import AsyncStorage from '#react-native-community/async-storage';
let authToken = '';
const axiosInstance = axios.create({
baseURL: '',
timeout: 150000,
headers: {
'Content-Type': 'application/json',
},
});
// request interceptor
axiosInstance.interceptors.request.use(
function (config) {
// Do something before request is sent
config.headers.Authorization = `Bearer ${authToken}`;
return config;
},
function (error) {
// Do something with request error
return Promise.reject(error);
}
);
const getAuthToken = async () => {
// asumming auth token was saved as string
authToken = await AsyncStorage.getItem('auth_data');
};
export const Get = async (route, data = {}) => {
// get and set auth token
await getAuthToken();
// route = /user?id=787878 or /user/787878
return await axiosInstance.get(route);
};
export const Post = async (route, data = {}) => {
await getAuthToken();
return await axiosInstance.post(route, data);
};

Axios Interceptors just working after page reload

I'm trying to send the Authorization header inside of all requests, when user is logged in my application.
but, whatever i do, it does not work.
Here is my axios instance and interceptor code.
import axios from 'axios'
import storage from '#/services/storageService'
const user = storage.getObject('currentUser')
export const http = axios.create({
baseURL: 'http://localhost/api',
})
http.interceptors.request.use((config) => {
if(user){
console.log(user)
config.headers.Authorization = user.token
}
return config
}, (err) => {
console.log(err)
return Promise.reject(err)
})
in my modules i'm importing the http instance like this
import { http } from '#/http'
export const getItems = () => {
return http.get('items').then( response => response.data)
}
So, clarifying, this code above works, but the header is not present on my request.
To get the interceptor working i need to force a page reload.
Anyone know how can i avoid this?
I solved my problem following #jacky's tip. Now my code runs as following.
import axios from 'axios'
import storage from '#/services/storageService'
export const http = axios.create({
baseURL: 'http://localhost/api',
})
http.interceptors.request.use((config) => {
let user = storage.getObject('currentUser')
if(user){
console.log(user)
config.headers.Authorization = user.token
}
return config
}, (err) => {
console.log(err)
return Promise.reject(err)
})

VUEJs : import service in main.js

I did create a service for authentication in vuejs
import axios from "axios";
var authenticateService = {
login: function(Username, Password) {
var form = new FormData();
form.append("username", Username);
form.append("password", Password);
return axios.post(LOGIN_API, form);
}
}
export default authenticateService;
I want to use this service in my main.js, where I have got an axios interceptor. I have interceptor which relogins if received any 401 response from server
import authenticateService from "./service/AuthenticationService";
import axios from "axios";
axios.interceptors.response.use(undefined, err => {
let res = err.response;
if (res.status === 401 && res.config && !res.config.__isRetryRequest) {
return new Promise((resolve, reject) => {
authenticateService//Error here. authenticateService undefined
.login('user1username', 'user1password')
.then(result => {
localStorage.setItem("expire_time", response.data.expires_in);
localStorage.setItem("access_token", response.data.access_token);
err.config.__isRetryRequest = true;
err.config.headers.Authorization =
"Bearer " + response.data.access_token;
resolve(err);
})
.catch(e => {
localStorage.removeItem("expire_time");
localStorage.removeItem("access_token");
reject(e);
});
});
}
});
This interceptor throws error saying "authenticateService is not defined". Though I have imported the authenticateService, I get it undefined. Not sure what I did wrong here.
Edit return axios object from login function