I am trying to use axios-auth-refresh library installed by npm. I stucked at problem i can't resolve. According to documentation i made code like this:
const refreshAuthLogic = (failedRequest) => {
let tokenData = JSON.parse(localStorage.getItem("REACT_TOKEN_AUTH"));
if (tokenData) {
return axios
.post(`${process.env.REACT_APP_API_URI}/Login/refresh-token`, {
departmentId: tokenData.departmentId,
jwtToken: tokenData.jwtToken,
userId: tokenData.userId,
})
.then((response) => {
console.log(response);
localStorage.setItem("REACT_TOKEN_AUTH", JSON.stringify(response.data));
failedRequest.response.config.headers["Authorization"] =
"Bearer " + response.data.jwtToken;
return Promise.resolve();
})
.catch((err) => {
console.log(`refreshed failed`);
logout();
return Promise.reject(err);
});
} else {
logout();
}
};
createAuthRefreshInterceptor(axios, refreshAuthLogic, {
statusCodes: [401],
});
Everything works almost perfect but catch never fire up so i can't logout user when refresh token expired. I get answer from api with 401 code but even if i try to put simple console log in .catch() nothing happen.
I have no idea what am i doing wrong? any ideas how to add logout() function to that code that will work?
Thanks to Sangam Rajpara, I've found a solution. You need to create a separate instance of axios.
const requestToken = axios.create();
Then use interceptors for the created instance. You can read about them on the axios page. Something like this:
requestToken.interceptors.response.use(
(res) => res,
(err) => {
// your log out action
logout();
return err;
}
);
Then, in your code instead of axios, use the instance that you created:
requestToken
.post(`${process.env.REACT_APP_API_URI}/Login/refresh-token`, {
departmentId: tokenData.departmentId, ...
You don't really need that "if" logic anymore
Related
I am building a react-native app, and I am starting to implement a more robust and sophisticated error-handling system, specifically for handling server errors when making http requests. Here is a basic example of how I am currently making http requests in my app.
I have a 'client.js' file which is essentially just a wrapper around axios. I have a 'get' method that looks like this:
const get = async (endpoint, config = {}) => {
try {
const result = await axios.get(domain + endpoint, config);
return result;
} catch (error) {
throw new Error(error.message);
}
};
Then, I have a file for each api endpoint that I need to access. For example, I have a 'posts.js' file, and in that file I have a 'getPosts' method:
const getPosts = async (userID, page, pageSize) => {
try {
const response = await client.get(
`${endpoint}?userID=${userID}&page=${page}&pageSize=${pageSize}`
);
return response.data;
} catch (error) {
throw new Error(error.message);
}
};
And then finally, in the component that is calling getPosts, I have a function that looks something like this:
const loadPosts = async () => {
try {
const response = await getPosts();
// do something with the response from the server
} catch (error) {
// display an error message to the client
}
}
Obviously this is a very simple example of what a request might look like, but this is the basic structure that I use throughout my app. The problem I am having is that it seems very repetitive and messy to have to wrap almost all of my functions in a try/catch block, and then basically raise an error object until I get to the function that is actually going to handle the error. Is there some sort of 'design method' for error handling that simplifies and centralizes this process? Perhaps something similar to an express-middleware when creating a node server? Or is this a standard way to handle errors in javascript?
Thank you to anyone who can help!
As you are using axios as the http library here, so you can take a look at axios interceptor in order to hook the response and do something with that before passing it to the consumer. This will help you to respond to errors raised from once cental place.
axios.interceptors.response.use((response) => {
return response;
}, function(error) {
// do what you want to do with the error.
return Promise.reject(error)
});
Or with ES5 syntax
axios.interceptors.response.use(function (response) {
// Do something with response data
return response;
}, function (error) {
// Not 200 Ok
// Do something with response error
return Promise.reject(error);
});
So I am implementing axios call cancelation in the project. Right now looking at axios documentation it seems pretty straight forward https://github.com/axios/axios#cancellation
So I did define variables on the top of my Vue component like
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
obviously on top of that is import axios from 'axios';
Then I have a method of fetching the API
On the top of the method I want to cancel out the request in case it is running so the last one cancels out if the user spams the filtering.
async fetchPartners(inputToClear) {
source.cancel();
...
try {
const response = await axios.get(`../partners?limit=1000${this.createRequestString()}`, {
cancelToken: source.token
});
// Here you can see I did add the cancelToken to the request
this.partners = response.data.data;
} catch (error) {
if (axios.isCancel(error)) {
console.log('Request canceled', error.message);
}
const fetchErrors = this.utilGlobalHandleErrorMessages(error);
this.utilGlobalDisplayMessage(fetchErrors.message, { type: 'error' });
return [];
} finally {
...
}
},
So it is pretty straight forward, just took the code from axios documentation I gave you above, it should be working by logic. But what is actually happening, it doesn't even allow me to fetch the call, it is already cancelled out before I can call it. On console it shows me
Request canceled undefined
It just catches the error as if I am cancelling the call, but how can it be, because I am source.cancel() before the call.
Anyone has any idea?
I hope you should throttle your requests instead of canceling the request.
Could you please try the following if throttle does not suit your requirement?
const CancelToken = axios.CancelToken;
let source;
async fetchPartners(inputToClear) {
if(source){
source.cancel();
}
...
source = CancelToken.source();
try {
const response = await axios.get(`../partners?limit=1000${this.createRequestString()}`, {
cancelToken: source.token
});
// Here you can see I did add the cancelToken to the request
this.partners = response.data.data;
} catch (error) {
if (axios.isCancel(error)) {
console.log('Request canceled', error.message);
}
const fetchErrors = this.utilGlobalHandleErrorMessages(error);
this.utilGlobalDisplayMessage(fetchErrors.message, {
type: 'error'
});
return [];
} finally {
...
}
}
So I'm trying for multiple ways to get error response status from my axios HTTP call and something weird is happening.
getData() {
axios.get(`/api/article/getObserved.php`, axiosConfig)
.then(response => {
console.log('success');
console.log(response);
})
.catch(err => {
console.log('error');
console.log(err.status);
console.log(err.response.status)
});
}
So I'm calling my getObserved endpoint and although it's returning http_response_code(503); it's going to .then() part because it console log 'success' string.
this is output from console:
GET http://localhost/obiezaca/v2/api/article/getObserved.php 503 (Service Unavailable)
success favouriteArticles.vue?31bd:83
I've done hundreds of calls like this and this .catch was always catching error even tho I'm not throwing exception like in other lenguages I would do. However I also tried like this:
getData() {
axios.get(`/api/article/getObserved.php`, axiosConfig)
.then(response => {
console.log('success');
console.log(response);
}, function (err) {
console.log('error');
console.log(err.status);
console.log(err.response.status);
})
.catch(err => {
console.log('error');
console.log(err.status);
console.log(err.response.status)
});
}
But it still doesn't console 'error' although I have this 503 bad request returned from my endpoint. Why?
I also would like to add that I dont think my endpoint is not working correctly because I was testing it with tests and manually by cURL and POSTMAN and everything was fine.
Edit since response is undefined when I don't get data from my endpoint and I need to handle only one error (there is data or not) I have just do something like this:
getData() {
axios.get(`/api/article/getObserved.php`, axiosConfig)
.then(response => {
if(response) {
this.articles = response.data.records;
} else {
this.noFavourite = true;
this.articles = [];
}
});
and it's working. I'll pray to not get into same issue with some call where I'll need to handle several different errors.
This issue was related to my httpInterceptor
import axios from 'axios';
import { store } from '../store/store';
export default function execute() {
axios.interceptors.request.use(function(config) {
const token = store.state.token;
if(token) {
config.headers.Authorization = `Bearer ${token}`;
//console.log(config);
return config;
} else {
return config;
}
}, function(err) {
return Promise.reject(err);
});
axios.interceptors.response.use((response) => {
return response;
}, (err) => {
console.log(err.response.status)
return Promise.reject(err); // i didn't have this line before
});
}
which wasn't returning promise on error response so after in promise of http call it somehow treated it as success. After adding return Promise.reject(err); inside my interceptor it's working fine
Below is my connection request code :
doLogin(this.login).then(response => {
var token = response.data.token;
localStorage.setItem('AUTH_TOKEN', JSON.stringify(token));
this.$router.push({name: 'Devices'});
});
}).catch(error => {
console.log(error.response.data.message);
});
the catch() part works fine for http errors (like 400, 404, 403..etc). But when my server is offline this script just throws net::ERR_CONNECTION_REFUSED. Is there any way to handle this error and let the front-end user know that the server is currently offline.?
Here is the doLogin() function just in case,
function doLogin(data) {
const url = 'http://localhost:3000/authenticate';
return axios.post(url,data);
}
You can try this in the catch part:
catch(error => {
if (!error.response) {
// network error
this.errorStatus = 'Error: Network Error';
} else {
this.errorStatus = error.response.data.message;
}
})
You may use interceptors:
axios.interceptors.response.use(
response => {
return response
},
error => {
if (!error.response) {
console.log("Please check your internet connection.");
}
return Promise.reject(error)
}
)
You should do the same validation that #chithra pointed out in the .then() because i'm having a weird issue when testing requests with my servers down, the "response" comes as if it was a success.
Also, on the .then() do it with response.status instead of response.error
By using npm; a standard package manager for the JavaScript runtime environment Node.js.
With npm:
npm i axios
Next, you should import Axios in your src/App.vue file
import axios from 'axios';
you will need to call it on a lifecycle hook. Here we will use the beforeCreated() lifecycle hook, this is because we will be able to retrieve sensitive data and events that are active with the beforeCreated hook.
data() {
return {
network: false,
}; },
beforeCreate() {
axios
.get("http://localhost:13172/api/product/getproducts")
.then((response) => {
console.log(response);
this.network = true;
})
.catch((error) => {
console.log(error), (this.network = false);
}); }
I am using fetch to make some API calls in react-native, sometimes randomly the fetch does not fire requests to server and my then or except blocks are not called. This happens randomly, I think there might be a race condition or something similar. After failing requests once like this, the requests to same API never get fired till I reload the app. Any ideas how to trace reason behind this. The code I used is below.
const host = liveBaseHost;
const url = `${host}${route}?observer_id=${user._id}`;
let options = Object.assign({
method: verb
}, params
? {
body: JSON.stringify(params)
}
: null);
options.headers = NimbusApi.headers(user)
return fetch(url, options).then(resp => {
let json = resp.json();
if (resp.ok) {
return json
}
return json.then(err => {
throw err
});
}).then(json => json);
Fetch might be throwing an error and you have not added the catch block. Try this:
return fetch(url, options)
.then((resp) => {
if (resp.ok) {
return resp.json()
.then((responseData) => {
return responseData;
});
}
return resp.json()
.then((error) => {
return Promise.reject(error);
});
})
.catch(err => {/* catch the error here */});
Remember that Promises usually have this format:
promise(params)
.then(resp => { /* This callback is called is promise is resolved */ },
cause => {/* This callback is called if primise is rejected */})
.catch(error => { /* This callback is called if an unmanaged error is thrown */ });
I'm using it in this way because I faced the same problem before.
Let me know if it helps to you.
Wrap your fetch in a try-catch:
let res;
try {
res = fetch();
} catch(err) {
console.error('err.message:', err.message);
}
If you are seeing "network failure error" it is either CORS or the really funny one, but it got me in the past, check that you are not in Airplane Mode.
I got stuck into this too, api call is neither going into then nor into catch. Make sure your phone and development code is connected to same Internet network, That worked out for me.