Why isn't react component catching axios error - javascript

I have the following code on python using flask
#bp.route("/test", methods=["GET"])
def test():
throw_error = True
if throw_error :
return jsonify(message="Throwing an error"), 405
return jsonify(message="Test message"), 200
on React I have a context setup with the following function
function testRequest(){
const response = axios.get('/api/test')
console.log(response)
}
I'm calling this function on a button click in another component by
async function handleButtonClick(e){
e.preventDefault();
try{
await testRequest();
}catch(error) { // DOESN'T EXECUTE??
console.error("Error occured")
setError("Error occurred in test method")
}
}
Why isn't the try catch, catching the 405 error?

You can only usefully await a promise. testRequest doesn't return a promise.
It triggers axios.get, assigns the promise to response, logs it, then returns undefined.
The try/catch doesn't touch the promise at all.
You could fix that with:
function testRequest(){
const response_promise = axios.get('/api/test')
console.log(response_promise)
return response_promise;
}
So the promise is being awaited inside the try/catch.

With below modification to your function, you will be able to catch error.
async function testRequest() {
const response = await axios.get('http://localhost:1337/sample/test');
return response;
}
async function handleButtonClick(e:any) {
e.preventDefault();
try {
await testRequest();
} catch (error) { // DOESN'T EXECUTE??
console.error("Error occured")
console.log(error.mes);
}
}

Related

Make second api call when there is no error on the first using Axios in React

I have three API calls which should be dependent on one another. The second API call should trigger only when the first succeeds.
With my current implementation, I'm getting a CORS error when the first API call is made and was able to catch the error in the catch block. However, I'm seeing that the second and third APIs calls are made irrespective of the error that got caught in the first API call.
Could anyone please advise?
const firstApiCall = async() => {
try {
await axios.post(
process.env.FIRST_API,
payload
);
]
} catch (err) {
console.log(`err`, err);
}
};
const secondApiCall = async() => {
try {
await axios.post(
process.env.SECOND_API,
payload
}
} catch (err) {
console.log(`err`, err);
}
};
const thirdApiCall = async() => {
try {
await axiosInstance.patch(
process.env.THIRD_API,
payload
);
} catch (err) {
console.log('err', err);
}
};
firstApiCall();
secondApiCall();
thirdApiCall();
You're calling the functions synchronously when you need to do it asynchronously:
async function performTasks() {
await firstApiCall();
await secondApiCall();
await thirdApiCall();
}
performTasks();
You can use the ES6 Promise implementation approacg. Therefore you should take a look to this ressource : [Promise][1]
With the promise approach you can react at each step / each API call.
[1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
async await functions work only in their local scope.
For example:
const myFunc = async() => {
try{
//...
await foo();
//All the code below will be blocked till
//the promise return by foo function is resolved
}
catch{
//...
}
}
const main = () => {
myFunc();
otherFunc();
//Other function calls
//Regardless of using async await in myFunc,
//the code bellow myFunc will be executed as
//async await will work only in myFunc block scope
}
main()
What you can do is, use async await inside the main function, so that the functions would be called in an order
const main = async () => {
await myFunc();
await otherFunc();
}

Axios instance promise.all error handling

I have the following code in my own async function that uses another imported function from module which is a custom wrap of axios inside try/catch block:
async function getCharacter (realmSlug, characterName) {
try {
const [{id, name, gender, faction, race, character_class, active_spec, realm, guild, level, last_login_timestamp, average_item_level, equipped_item_level}, {pets, unlocked_battle_pet_slots},{mounts}] = await Promise.all([
getCharacterSummary(realmSlug, characterName), -- custom axios instance
getCharacterPetsCollection(realmSlug, characterName),
getCharacterMountsCollection(realmSlug, characterName)
])
....
return result;
} catch (error) {
console.log(error.code);
if (error.response.status === 404 || error.response.status === 403) {
console.error(`${getCharacter.name},${characterName}#${realmSlug}`);
}
return { name: characterName, realm: realmSlug }
}
}
The problem is that if I use promise.all according to Stackoverflow 1,2 I can not handle errors. So the problem is when I call function to execute, my errors doesn't handle in (catch) block. At all. Even if I don't need print them, anyway I receive messages in console about 404 errors, but console.log(error.code) still gives me nothing. For example:
So is there any way to handle this annoying error messages in console somehow?
For example using .catch somewhere? Or using for await ... of or rxJS instead if it's possible?
Exporting function and using .catch
Even if I export this function getCharacter in another .js file and use the following code:
const getCharacter = require('./getCharacter');
let bulkCharacters = [{realmSlug, characterName},{realmSlug, characterName},... ,n] //array of characters for getCharacter request
const promises = bulkCharacters.map(async ({realmSlug, characterName}) => {
try {
return await getCharacter(realmSlug, characterName);
} catch (e) {
console.log(e)
}
});
let test = await Promise.all(promises)
.catch(function(arrayOfPromises, err) {
// log that I have an error, return the entire array;
console.log('A promise failed to resolve', err);
return arrayOfPromises;
})
.then(function(arrayOfPromises) {
console.log(arrayOfPromises)
})
;
console.log('stop')
I still receive errors in console, without triggering catch block inside getCharacter function or this file in which this function was imported and catch block is outside the function.

Async function Uncaught (in promise) undefined error

I'm trying to do some validations before creating/updating an entry as shown below:
async save(){
return new Promise((resolve, reject)=>{
if(!this.isCampaignValid){
this.handleError()
reject()
}
else{
this.$store
.dispatch('updateCampaign')
.then((res)=>{
resolve()
this.showNotification(res.message, 'success')
})
.catch(error=>{
this.showNotification(error.message, 'error')
reject()
})
}
})
},
the isCampaignValid is a computed value which computes the validity.
If the campaign is not valid, then I'm getting an error in the console as below:
Uncaught (in promise) undefined
The this.handleError() function works too. How can handle this promise error situation?
Just in case handleError() throws, try:
if (!this.isCampaignValid) {
try {
this.handleError()
} catch (e) {
console.error(e);
}
reject()
}
First of all, you don't need to return a promise in an async function. It implicitly returns one, resolving with the value returned by the function or rejecting with the error object if the function throws. Although you could return a promise and JS unpacks it for you, it's unneeded code.
That said, because async returns a promise, you'll have to catch that promise too. Since your first conditional block just throws an error but doesn't catch it, the promise returned by save will reject. You need to handle that rejection.
Here's a simplified version of your code to see where it's happening.
async save(){
if(!this.isCampaignValid){
this.handleError()
// Throwing an error in an async function is equivalent to a reject.
throw new Error('Campaign is not valid') // Here
}
else{
try {
const res = await this.$store.dispatch('updateCampaign')
this.showNotification(res.message, 'success')
} catch (e) {
this.showNotification(error.message, 'error')
}
}
},
// When you call save, catch the error
yourObject.save()
.then(() => {...})
.catch(() => {...})
// If your call is in an async function, you can try-catch as well
try {
await yourObject.save()
} catch(e) {
// It failed.
}

How to re-throw the catched error in axios catch() block

In axios, why throw new Error() is not allowed inside catch()?
I am in such requirement, where if an error is returned by the server, the catch block should throw an error, which later on will be handled by redux-saga and appropriate action would be dispatched.
The API call:
export const userSignupApi = userDetails => {
const endpoint = `${URL_ROOT}${URN_SIGNUP}`;
axios
.post(endpoint, userDetails)
.then(response => {
console.log("Response: ", response);
//do something with the response
})
.catch(error => {
throw new Error(error.response.data.message);
});
};
I am getting Unhandled Rejection (Error) because of the above catch block.
Below is my saga which handles the operation:
import { call, takeLatest, put } from "redux-saga/effects";
function* handleUserSignup(action) {
try {
yield call(userSignupApi, action.userDetails);
yield put(userSignupSuccess()); //dispatching success action
} catch (error) {
yield put(userSignupFail(error)); //dispatching error action
}
}
function* watchUserSignup() {
yield takeLatest(NEW_USER.SIGNUP, handleUserSignup);
}
Edit: Why I want the above code structure? Because this makes easy to unit test the API code and the saga code.
The Promise created in userSignupAPI isn't being used anywhere (it's not even being returned), so when an error is thrown inside catch, the Promise chain resolves to an (uncaught) rejected Promise, resulting in the error.
In the caller of userSignupAPI, you should await the call, so that the try/catch inside handleUserSignup will see the thrown error:
export const userSignupAPI = userDetails => {
const endpoint = `${URL_ROOT}${URN_SIGNUP}`;
return axios
.post(endpoint, userDetails)
.then(response => {
console.log("Response: ", response);
})
.catch(error => {
throw new Error(error.response.data.message);
});
};
async function* handleUserSignup(action) {
try {
yield await call(userSignupApi, action.userDetails);
yield put(userSignupSuccess()); //dispatching success action
} catch (error) {
yield put(userSignupFail(error)); //dispatching error action
}
}
function* watchUserSignup() {
yield takeLatest(NEW_USER.SIGNUP, handleUserSignup);
}
(make sure that call returns the Promise returned by userSignupApi)
I got this working. I was doing it completely wrong. As suggested by #certianPerformance and after reading some questions and github issues, I got the right way to handle this. Instead of returning the api response, I should have returned the promise.
Here is the solution:
export const userSignupApi = userDetails => {
const endpoint = `${URL_ROOT}${URN_SIGNUP}`;
return axios.post(endpoint, userDetails);
};
Saga:
import { call, takeLatest, put } from "redux-saga/effects";
function* handleUserSignup(action) {
try {
const response = yield call(userSignupApi, action.userDetails);
response.then(response => {
const location = response.headers.location;
put(userSignupSuccess(location));
put(newUserWelcomeNote("Welcome user"));
});
} catch (error) {
const errorMessage = error.response.data.message;
yield put(userSignupFail(errorMessage));
}
}
function* watchUserSignup() {
yield takeLatest(NEW_USER.SIGNUP, handleUserSignup);
}
You are using try catch because you don't want to throw error in browser console you want to handle in catch. Throwing error in catch will remove its purpose.If you want to throw error remove try catch(which is not a recommended way)
UPDATE
For axios catch method catches any error thrown by api url. If you don't want to catch error and show it in browser, you can remove catch block or you can call the action which handles error. For more information about promise catch you can refer here

Async function always return undefined

im using nodejs 8. I've replaced promise structure code to use async and await.
I have an issue when I need to return an object but await sentence resolve undefined.
This is my controller method:
request.create = async (id, params) => {
try {
let request = await new Request(Object.assign(params, { property : id })).save()
if ('_id' in request) {
Property.findById(id).then( async (property) => {
property.requests.push(request._id)
await property.save()
let response = {
status: 200,
message: lang.__('general.success.created','Request')
}
return Promise.resolve(response)
})
}
}
catch (err) {
let response = {
status: 400,
message: lang.__('general.error.fatalError')
}
return Promise.reject(response)
}
}
In http request function:
exports.create = async (req, res) => {
try {
let response = await Request.create(req.params.id, req.body)
console.log(response)
res.send(response)
}
catch (err) {
res.status(err.status).send(err)
}
}
I tried returning Promise.resolve(response) and Promise.reject(response) with then and catch in the middleware function and is occurring the same.
What's wrong?
Thanks a lot, cheers
You don't necessarily need to interact with the promises at all inside an async function. Inside an async function, the regular throw syntax is the same as return Promise.reject() because an async function always returns a Promise. Another thing I noticed with your code is that you're rejecting promises inside a HTTP handler, which will definitely lead to unexpected behavior later on. You should instead handle all errors directly in the handler and act on them accordingly, instead of returning/throwing them.
Your code could be rewritten like so:
request.create = async (id, params) => {
let request = await new Request(Object.assign(params, { property : id })).save()
if ('_id' in request) {
let property = await Property.findById(id)
property.requests.push(request._id)
await property.save()
}
}
And your http handler:
exports.create = async (req, res) => {
try {
await Request.create(req.params.id, req.body)
res.send({
status: 200,
message: lang.__('general.success.created','Request')
})
} catch (err) {
switch (err.constructor) {
case DatabaseConnectionError: // Not connected to database
return res.sendStatus(500) // Internal server error
case UnauthorizedError:
return res.sendStatus(401) // Unauthorized
case default:
return res.status(400).send(err) // Generic error
}
}
}
Error classes:
class DatabaseConnectionError extends Error {}
class UnauthorizedError extends Error {}
Because you have that try/catch block inside your http handler method, anything that throws or rejects inside the Request.create method will be caught there. See https://repl.it/LtLo/3 for a more concise example of how errors thrown from async function or Promises doesn't need to be caught directly where they are first called from.

Categories