my current function looks like this:
import axios from 'axios';
export const GET_LOCATIONS = 'GET_LOCATIONS';
export function fetchLocals() {
const request = axios.get('http://localhost:3001/api')
.then(function(response) {
console.log(response.data)
})
.catch(function (error) {
console.log(error);
});
return {
type: GET_LOCATIONS,
payload: request
};
}
I want to be able to get the response.data outside of this so I can access its information and publish them!
Just return response.data from the .then handle, and it will be fine:
export function fetchLocals() {
const request = axios.get('http://localhost:3001/api')
.then(function(response) {
console.log(response.data);
return response.data;
})
.catch(function (error) {
console.log(error);
return Promise.reject(error);
});
return {
type: GET_LOCATIONS,
payload: request
};
}
Now you can call the function like this:
fetchLocals().payload
.then(data => {
// `data` will be `response.data` here
});
Note that a Promise.reject call is required in the catch handle to make the subsequent handlers identify a rejected promise.
Related
I'm learning React and I'm using axios and JWT for authentication. I have written an interceptor to refresh the token automatically:
privateAxios.interceptors.response.use(
(response) => {
return response;
},
(error) => {
const { config, response } = error;
const originalRequest = config;
if (response?.status === 401) {
apiProvider
.refreshToken()
.then(() => {
let headers = getAuthHeaders();
privateAxios.defaults.headers = headers;
originalRequest.headers = headers;
return privateAxios(originalRequest);
})
.catch((err) => {
logout();
return Promise.reject(err);
});
}
return Promise.reject(error);
}
);
On my component I have the following:
api.post(data)
.then(() => {
showSuccessFeedbackForm();
reloadTable();
handleClose();
})
.catch((error) => {
setAlertInfos({
message: JSON.stringify(error.response.data),
severity: "error",
});
setShowAlert(true);
})
.finally(() => {
setIsLoaded(true);
});
My problem is that I want to continue with the component's normal "flow" (i.e., showSuccessFeedbackForm() and reloadTable() and handleClose()) if the token needed to be refreshed (when the code reaches return privateAxios(originalRequest)).
How can I accomplish this?
It looks like you should just have to return the apiProvider.refreshToken()... call. After return privateAxios(originalRequest); returns, then return Promise.reject(error); is executing which causes the front-end to receiving an rejection not a resolution.
Consider this intercepted error which does not throw an error to the frontend which still "resolves":
axios.interceptors.response.use(
(res) => res,
(err) => {
console.log("##### AXIOS ERROR #####");
dispatch(increment());
}
);
Simply changing it to this causes the front-end to catch an error which is what your code is essentially doing:
axios.interceptors.response.use(
(res) => res,
(err) => {
console.log("##### AXIOS ERROR #####");
return Promise.reject();
}
);
I use axios interceptors to get the error. in some cases that I have error I do not want to return to the catch or then callback.
How I do it in axios? because if I dont return value it go to the next, but if I return Promise.reject it go to the catch.
I want when I have error in interceptors, not continue forward to the callback.
codesandbox.io
import axios from "axios";
axios.interceptors.response.use(
(response) => response,
(error) => {
console.log({ error });
// do not return to the catch/then in foo please! <-- HOW?
return Promise.reject(error);
}
);
const foo = () => {
axios
.post("https://httpstat.us/500")
.then((r) => {
console.log({ r });
})
.catch((err) => {
console.log({ err });
});
};
foo();
you can return a resolve promises in the error function
axios.interceptors.response.use(
(response) => response,
(error) => {
console.log({ error });
return Promise.resolve();
}
);
I'm performing an API call to Bing Web Search API and running into an error with the response.
Here's the code:
await webSearchApiClient.web.search(searchText).then(result => {
console.log('Results API', result)
return result
}).catch((err) => {
throw err;
})
The issue I'm running into is that the result does come back (the console log 'Results API' prints the expected return values), but the return statement isn't passing the value along. The rest of the code is written to be asynchronous, and when I print the values in the code calling the API function I get this:
Line 1: Results API {"_type": "SearchResponse","queryContext": {"originalQuery":...
Line 2: Returned Results undefined
I've tried setting the result to other variables with no success
I'm using redux as well, here's the code for the dispatch call and the code in the redux action (the second console log is the the redux actions):
const onSearchResults = async () => {
dispatch(getWebResults(searchText))
dispatch(getImageResults(searchText))
}
export const getWebResults = (searchText) => {
return async dispatch => {
const onStart = () => {
dispatch({ type: GET_WEB_RESULTS_STARTED });
}
const onSuccess = (response) => {
dispatch({ type: GET_WEB_RESULTS_SUCCESS, payload: response });
return response;
}
const onError = (error) => {
dispatch({ type: GET_WEB_RESULTS_FAILURE, payload: error });
return error;
}
try {
onStart();
const webResults = await BingWebSearchApi(searchText);
console.log('Returned Results', webResults)
return onSuccess(webResults)
} catch(error) {
return onError(error)
}
}
}
Instead of doing this
await webSearchApiClient.web.search(searchText).then(result => {
console.log('Results API', result)
return result
}).catch((err) => {
throw err;
})
Since the return statement is for the then function scope, you should return the promise like this
return webSearchApiClient.web.search(searchText);
And then in your redux actions do something like
(...)
try {
onStart();
BingWebSearchApi(searchText).then((webResults)=> {
console.log('Returned Results', webResults);
onSuccess(webResults);
});
} catch(error) {
return onError(error)
}
Hi I'm new so sorry if my question does not formulate properly.
I want to define a promise from axios js in a global function.
Here I want to handle / catch the 401 status globally and logout the user.
I do not want to handle it in every single query.
Here my source global function to handle a request:
export function requestData (url, payload = {}) {
return axios.post(url, payload)
.then(response => {
return response.data
})
.catch(error => {
if (error.response.status === 401) {
logout()
} else {
return error
}
})
}
And here a example function I use on a controller:
requestData('/api/persons', {options: this.options, search: search})
.then(data => {
this.data = data
})
.catch(error => {
this.error = error.toString()
})
My Problem is that the promise catch in my controller will not fire when there is an exception. How to realize this?
change return error in your requestData function to throw error
As per the Axios docs
You can intercept requests or responses before they are handled by then or catch.
You're going to want to use the Response Interceptor:
axios.interceptors.response.use(function(response) {
// Do something with response data
return response;
}, function(error) {
// Do something with response error
if (error.status === 401) {
logout()
}
return Promise.reject(error);
});
Replacing return error by throw error is the half work.
When I'm right the throw error in promise catch will not invoke the next promise .catch statement. This will work in the .then statement.
This way it should work:
export function requestData (url, payload = {}) {
return axios.post(url, payload)
.then(response => {
return response.data
})
.catch(error => {
if (error.response.status === 401) {
logout()
} else {
return error
}
})
.then(result => {
if (result instanceof Error) {
throw result
} else {
return result
}
})
}
I have a bit of a long login process that relies on 3 api calls that looks like this at the moment:
export const authenticationSignIn = (email, password) =>
(dispatch) => {
dispatch({ type: AUTHENTICATION_REQUEST });
apiAccountStatus(email, password)
.then(({ data }) => {
const status = data.status;
if (status === 'ACCOUNT_CREATED') {
apiSignIn(email, password)
.then(({ data: sessionData }) => {
apiIndexAccounts()
.then(({ data: accountsData }) => {
dispatch({ type: AUTHENTICATION_SUCCESS });
window.router.transitionTo('/dashboard/home');
});
});
} else if (status === 'SOMETHING ELSE') {
// TODO: HANDLE SOMETHING ELSE
}
})
.catch(({ response }) => {
dispatch({ type: AUTHENTICATION_FAILURE });
dispatch(notificationShow('ERROR', response.data.type));
});
};
As you can see this function is quiet verbose, but each nested api call relies on data returned from previous and I am trying to clean this up as much as possible (dispatch bits are redux specific, but these essentially fire whatever is passed in). At the end you will see a catch statement, my question is will this catch statement work for all of the promisses or only apiAccountStatus?
At the end you will see a catch statement, my question is will this catch statement work for all of the promises?
No, it only works for the outer promise, the one returned by the then call. This needs to be rejected for the catch callback to be activated. To get this promise rejected, either apiAccountStatus(…) must reject or the then callback must throw an exception or return a promise that will be rejected.
This last thing is what you were missing - you were creating more promises inside that then callback, but you weren't returning them so that they will not chain. You have to do
export function authenticationSignIn(email, password) {
return (dispatch) => {
dispatch({ type: AUTHENTICATION_REQUEST });
apiAccountStatus(email, password)
.then(({data: {status}}) => {
if (status === 'ACCOUNT_CREATED') {
return apiSignIn(email, password)
// ^^^^^^
.then(({ data: sessionData }) => {
return apiIndexAccounts()
// ^^^^^^
.then(({ data: accountsData }) => {
dispatch({ type: AUTHENTICATION_SUCCESS });
window.router.transitionTo('/dashboard/home');
});
});
} else if (status === 'SOMETHING ELSE') {
// TODO: HANDLE SOMETHING ELSE
}
})
.catch(({ response }) => {
dispatch({ type: AUTHENTICATION_FAILURE });
dispatch(notificationShow('ERROR', response.data.type));
});
};
}