I've centralized all my API calls in a unique file API.js as below:
API.js
Class APIContextProvider extends Component {
async apiCallTest() {
var url = random_url
const options = {
url: url,
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json;',
},
};
return await axios(options)
.then(response => {
if (response.status === 200) {
return response.data
}
}).catch(error => {
console.log(error.response.status)
}
);;
}
Then I call my API from another component:
OutsideClass.js
async componentDidMount() {
this.context.apiCallTest().then(data => {
// How can I prevent this then() to run when catch() happens?
});
}
The order is which everything is done is: then().catch().then().
What I want is to prevent the last then(). from happening if a specific error is caught (like 401) since I want global error handling.
Looked everywhere but can't find a solution...
Thank you!
If you want to catch exception globally, then use axios interceptors in your bootstrap file just after
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
axios.interceptors.response.use(
function (response) {
return response;
},
function (error) {
// handle error
if (error.response.status === 422)
return error;
if (error.response.status === 401)
alert(error.response.status + ': ' + error.response.data.message);
});
You can throw the error again in you catch, and it will avoid the then and go to the next catch.
await axios(options)
.then(response => {
if (response.status === 200) {
return response.data
}
}).catch(error => {
if (error.response.status === 401) {
throw error;
}
console.log(error.response.status)
}
Related
I have been trying to working with Github Gists API, specifically the "Star a Gist"functionality but I am noticing a strange behavior when I send a request via my React app.
Here's the code for the request:
const starNote = async (noteId, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
"Content-Length": "0",
},
}
try {
const response = await axios.put(`${API_URL}/${noteId}/star`, config, {
noteId: noteId,
})
console.log("request sent")
if (response.status === 204) {
console.log("working", response)
return true
}
} catch (error) {
if (error.response.status === 404) {
console.log(error)
}
}
}
And here's the code for the slice function:
export const starNote = createAsyncThunk(
"notes/starNote",
async (noteId, thunkAPI) => {
try {
const token = thunkAPI.getState().auth.user.accessToken
return await notesService.starNote(noteId, token)
} catch (error) {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString()
return thunkAPI.rejectWithValue(message)
}
}
)
The action gets triggered correctly but the request doesn't go through the:
console.log("request sent")
part and goes straight to the error. If you send a GET request, it gives a 404 error if you haven't starred a gist. But for the PUT request, why does it go straight to the error and not send the request. If i try the same with Postman it works correctly and returns a
response.status: 204
What am I doing wrong here?
Okay so what I did was insert this in the PUT request:
{ noteId: noteId }
And it worked.
Here's the complete code of the call:
const starNote = async (noteId, token) => {
const config = {
headers: {
Authorization: `Bearer ${token}`,
"Content-Length": "0",
},
}
try {
const response = await axios.put(
`${API_URL}/${noteId}/star`,
{ noteId: noteId },
config
)
console.log("request sent")
if (response.status === 204) {
console.log("working", response)
return true
}
} catch (error) {
if (error.response.status === 404) {
console.log(error)
}
}
}
I am still not sure why it's necessary but this is what it needed.
I am using the below code as an interceptor in my React JS app for getting token back but unfortunately, it is not working. Refresh token returns new idToken and updates local storage data correctly. The same code I'm using some other application which works fine. One main difference is that I currently use React 18 and the previous 16. I struggled to identify the problem but failed. Your help will be appreciable.
axios.interceptors.response.use(
(response) => {
return response;
},
(error) => {
if (error.response.status === 401) {
// console.log(error.response.data.code)
let usersData = JSON.parse(localStorage.getItem("userData"));
const refreshToken = usersData.refreshToken;
return axios
.post(
`${api_base_url}/auth/authentication/refresh_token`,
JSON.stringify({
refresh_token: refreshToken,
})
)
.then((response) => {
usersData["accessToken"] = response.data.data.accessToken;
usersData["idToken"] = response.data.data.idToken;
setSessionStorage("userData", usersData);
error.response.config.headers[
"Authorization"
] = `Bearer ${response.data.data.idToken}`;
return axios(error.response.config);
})
.catch((error) => {
if (error.response.data.code !== "TOKEN_EXPIRED") {
return;
}
localStorage.clear();
window.location = "/login";
});
}
return Promise.reject(error);
}
);
function getIRequestProp(severType, isMultipart, isSocial) {
const serverUrl = severType ? social_api_base_url : api_base_url;
let userData = JSON.parse(localStorage.getItem('userData'));
let idToken;
idToken = userData !== null ? userData['idToken'] : '';
let content_type;
if (isSocial) {
content_type = 'application/x-www-form-urlencoded'
} else {
content_type = isMultipart ? 'multipart/form-data' : 'application/json'
}
return {
serverUrl: serverUrl,
requestHeader: {
'Content-Type': content_type,
'Accept-Language': DEFAULT_LANGUAGE,
Authorization: `Bearer ${idToken}`
}
};
}
async function post(url, body, isSocialServer, isMultipart) {
const {serverUrl, requestHeader} = getIRequestProp(isSocialServer, isMultipart);
return axios.post(serverUrl + url, body, {
headers: requestHeader
});
}
So, I call API like this:
AxiosServices.post(ApiUrlServices.SOCIALS_UPDATE_LINKS(UserInfo.userId), payload, false)
.then(response => {})
What i figured out that return axios(error.response.config); is not sending authorization token in API request headers and trying request infinitely. But consoling error.response.config shows token sets in the config correctly.
Adding an additional modification of axios request, I solved my problem.
axios.interceptors.request.use(request => {
// Edit request config
let usersData = JSON.parse(localStorage.getItem('userData'));
request.headers['Authorization'] = `${usersData.idToken}`;
return request;
}, error => {
return Promise.reject(error);
});
when i am trying to perform this task to change password, everything works fine if the response is 200 and it also gives me the pop up window, but if its not it dosent perform the else statement,it like no else. completely ignored.
here is the code
const submitForm = () => {
let form_data = new FormData();
form_data.append('old_password', formValues.oldpass);
form_data.append('new_password', formValues.newpass);
try {
axios.put(baseUrl + '/change-password/', form_data,
{
headers: {
'Authorization': `Token ${token}`
}
}
).then((response) => {
const Swal = require('sweetalert2');
console.log(response.data);
if (response.status === 200) {
Swal.fire(
'Great!',
'Password updated successfully',
'success'
)
}
else {
alert('error ', 'password has not been changed !!');
}
});
} catch (error) {
console.log(error);
}
};
please help i am new to react and i`ve had this issue for days.
Axios throws the response if the status code is something else than 2xx. Which means that if you get e.g. 4xx or 5xx the then clause is not run. Instead you need a catch clause that will handle this case.
.then((response) => {
const Swal = require('sweetalert2');
console.log(response.data);
Swal.fire('Great!', 'Password updated successfully', 'success')
}).catch((response) => {
alert('error ', 'password has not been changed !!');
console.log(error);
});
In this case you can remove try-catch as it won't catch any errors.
Optionally you can await the result of the axios call to have the current catch clause catch the error. Then you'll also need the function to be async.
const submitForm = async () => {
let form_data = new FormData();
form_data.append('old_password', formValues.oldpass);
form_data.append('new_password', formValues.newpass);
try {
await axios.put(baseUrl + '/change-password/', form_data,
{
headers: {
'Authorization': `Token ${token}`
}
}
).then((response) => {
const Swal = require('sweetalert2');
console.log(response.data);
Swal.fire('Great!', 'Password updated successfully', 'success')
});
} catch (error) {
console.log(error);
alert('error ', 'password has not been changed !!');
}
};
https://axios-http.com/docs/handling_errors
// Login Method
const postLogin = (url, data) => {
return axios.post(url, data).then(response => {
if (response.status === 400 || response.status === 500)
throw response.data;
console.log(response);
return response;
}).catch(err => {
console.log(err);
throw err[1];
});
}
The above login method always log the following error:
Error: Request failed with status code 404
at createAxiosError (utils.js:147:1)
at Object.settle (utils.js:123:1)
at handleRequest (handle_request.js:124:1)
at index.js:26:1
at new Promise (<anonymous>)
at MockAdapter.<anonymous> (index.js:25:1)
at dispatchRequest (dispatchRequest.js:52:1)
On call
const response = yield call(postLogin, 'http://localhost:8080/users/verify_login/', {
email: user.username,
password: user.password,
headers: {
"Content-Type": "application/json",
"accept" : "application/json",
}});
Though the http://localhost:8080 is running. We are using React. How to solve this?
You can try using async await for better debugging your code.
const postLogin = async (url, data) => {
try{
var response = await axios.post(url, data)
return response
}catch(e){
// Handle catch
}finally{
// Handle finally
}
}
Im trying to use axios interceptor with refresh token but when my token has expired. My error code within in interceptors.response is not executing. What can i do to fix this issue, i am also getting a status code of 200 which does not make much sense to me.
Also here is my code
proctedInstance.interceptors.request.use(
async config => {
const accesstoken = localStorage.getItem('accesstoken');
config.headers = {
'Authorization': `Bearer ${accesstoken}`,
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
}
return config;
},
error => {
Promise.reject(error);
}
)
proctedInstance.interceptors.response.use((response) => {
console.log(response);
return response
},
function (error) {
const originalRequest = error.config;
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true;
return axios.post('http://localhost:4000/refresh_token')
.then(res => {
if (res.status === 200) {
localStorage.setItem('accesstoken', res.data.accesstoken)
console.log('my token res.data.accesstoken', res.data.accesstoken);
axios.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('accesstoken');
return axios(originalRequest);
}
})
}
return Promise.reject(error);
})
export const onProtected = async () => {
const results = await (await proctedInstance.post('/protected')).data
if(results.data === 'This is protected data.'){
return true;
} else
return false;
}
any help is appreciated
Try letting it like this:
proctedInstance.interceptors.response.use(
function (response) {
return response;
},
function (error) {
const access_token = localStorage.getItem("accesstoken");
if (error.response.status === 401 && access_token) {
//Your logic to refresh token and reattempt request
} else {
console.error(error);
}
return Promise.reject(error);
}
);