Reputation: 51
i am working with reactjs on front end the issue is after certain time period the accessToken is expired and server send status of 401(unauthorized) then i need to send refresh token back to server it works fine until i manually send the refresh token i set the setInterval function but thats not a good approach how to automatically send it when token is expired. i also google it but everyone is talking about creating middleware anyone please give me the hint how to create that middleware or any other solution or link any article related to it . i created this but this didnt works for me however when server send status of 401 then middleware ran but it dosent dispatch my refreshToken() function
const customMiddleWare = store => next => action => {
axios.interceptors.response.use(function (response) {
return response;
}, function (error) {
if(error.status === 401) {
// do something when unauthorized
store.dispatch(refreshToken());
}
return Promise.reject(error);
});
console.log("Middleware triggered:", action);
next(action);
}
By the way i am using redux, redux-thunk and axios. thanks,
Upvotes: 0
Views: 2579
Reputation: 834
some time ago i used to use the next way:
First of all i created some api folder, where each function returns data for axios requests
// /api.js
export function signIn (data) {
return {
method: 'post',
api: '/sign-in'
data: data
}
}
export function signUp (data) {
return {
method: 'post',
api: '/registration'
data: data
}
}
then i generated action type by specific rule, like: SIN_IN_REQUEST, where: SIGN_IN means signIn function in /api.js; REQUEST means that you need to do api request. As result my middleware looked like the next:
// request middleware
const instance = axios.create({
baseURL: '/api'
});
function camelize(str) {
return str.replace(/(?:^\w|[A-Z]|\b\w)/g, function(word, index) {
return index === 0 ? word.toLowerCase() : word.toUpperCase();
}).replace(/\s+/g, '');
}
const customMiddleWare = store => next => action => {
if (!action.type.endsWith('_REQUEST')) {
next();
return;
}
const methodName = action.type.replace('_REQUEST', ''); // removed _REQUEST from action type
const camelCaseMethodName = camelize(methodName); // the result is "signIn"
const method = api[camelCaseMethodName];
if (!method) {
next();
return;
}
const dataForRequest = method(action.payload);
try {
const response = await instance(dataForRequest);
const newActionType = action.type.replace('_REQUEST', '_SUCCESS');
dispatch({
type: newActionType,
payload: {
requestPayload: action.payload,
response: response,
}
})
} catch(error) {
if (error.status === '401') {
dispatch(refreshToken());
next();
return;
}
const newActionType = action.type.replace('_REQUEST', '_FAILURE');
dispatch({
type: newActionType,
payload: {
requestPayload: action.payload,
error: error,
}
})
}
next();
}
After that you can easily manage any api request in your application like that:
function someTHunkMethod(username, password) {
return (dispatch, getState) => {
dispatch({
type: 'SIGN_IN_REQUEST',
payload: {
username,
password
}
})
}
}
function oneMoreThunk(data) {
return (dispatch, getState) => {
dispatch({
type: 'GET_USERS_REQUEST',
payload: data
})
}
}
And in reducer do something like that
...
switch (action.type) {
case 'SIGN_REQUEST':
return {
isLoading: true,
user: null
}
case 'SIGN_SUCCESS':
return {
isLoading: false,
user: action.payload.response.data
}
case 'SIGN_FAILURE':
return {
isLoading: false,
user: null
}
default:
return state
}
Upvotes: 2