Reading response from async/await pattern in try/catch block - javascript

I'm making an API request using the async/await pattern in a try/catch block..
async myRequest(data) {
try {
await api.post('/my-endpoint/', data).then((response) => {
console.log(response.data)
});
} catch (ex) {
// WANT TO READ RESPONSE DATA HERE
}
}
If the request succeeds without errors, I am able to read the response with the .then() method.
If the request fails, this API returns a 422 code that triggers the try/catch exception.
However, if the request fails, this API still returns some data in the response body that I would like to to read but unable to because catch is triggered and .then() is never run.
How can I get the response body from the async function within the catch block?

Try this if you are on Axios lib:
catch (e) {
console.log(e.response.data);
}
console.log uses the toString method to format Error objects so it is hard to find the response property if you only log e (error).
Docs: https://axios-http.com/docs/handling_errors

The error object is stored in ex so you can log the error with
} catch (ex) { console.log(ex) }
One of the problems you are making is putting the .then after you call your API. When you are using the try-catch block you don't need to do the then because you can save the result into a variable.
One of the benefits of the try-catch block is that the errors are handled and you can do multiple async calls
async myRequest(data) {
try {
const response = await api.post('/my-endpoint/', data)
console.log(response.data)
} catch (ex) {
console.log(ex)
}
}

If you want to retrieve the response data from a catch block, you can do it technically.
See the following code.
const myRequest = async () => {
try {
const data = await fetch('https://jsonplaceholder.typicode.com/xxx/1').then((result)=> {
// You can change the status code to 422
if (result.status === 404) {
throw new Error('You can put your data here.')
// Make sure the argument you passed in Error is a string
}
return result.json()
})
} catch(e){
console.log(e.message);
}
}
myRequest()

Related

Mock a thrown exception

Is there a way to mock what a thrown exception in the try catch block? I want to test my function that the url string in error.message is indeed replaced with replacedURL string. How can I easily test it or mock the thrown exception to an object with this URL.
async function getUsers() {
try {
const response = await fetch('/api/users');
if (response.status >= 400) {
console.error('Could not fetch users');
return;
}
const users = response.json();
return users;
} catch (error) {
let message = error.message;
if (message) {
message = message.replace(/https:\/\/some.url.com /g, 'replacedURL');
delete error.message;
}
console.error('error', error);
}
}
Here's my test
test('url in error message is replaced', () => {
expect(getUsers()).toThrow('replacedURL');
})
You might want to actually throw an error in your function for it to be caught by toThrow.
Also, I'd recommend that your test doesn't actually tries fetching from the API (unless you're sure that's what you want it to do). Instead, consider using a custom caller (which can extend fetch) which you can then mock the response for, like const caller = jest.fn().mockRejectedValue({ message: 'https:://some.url.com' });

How to use a conditional validation after Axios call in Vue app

I have a Vue application where I make a POST request to my backend. I am now trying to call a validation method after the response from my backend returned back an error to my frontend. But for some reason my code is not executed:
UPDATED QUESTION CODE:
validateFormInput(){
this.$refs.form.validate()
},
saveSelectionVoter() {
var pageURL = window.location.href;
var lastURLSegment = pageURL.substr(pageURL.lastIndexOf('/') + 1);
this.votersSelectArray.voterAvailableTimes = [...this.votersSelectArray.voterAvailableTimes, ...this.selected]
console.log(JSON.stringify( this.votersSelectArray))
axios.post("http://localhost:8080/api/votercontroller/",
this.votersSelectArray,
{
params: {
meetingName: lastURLSegment,
}
},
).then(function(response){
})
.catch(function (error){
this.validateFormInput()
console.log(error)
})
this.selected = []
},
This causes a new error:
TypeError: Cannot read property 'validateFormInput' of undefined
always have a catch to see the error return
axios return you a promise so it captures the error if there is any
axios.post('url')
.then((res) => {
// do somthing
}).catch(err){
console.log(err)
}
You can either use the callback method to catch the response/error or use the Promise way, which is my favorite because of scope and readability.
You start by declaring your function with async
async saveSelectionVoter() {
Then you use a try/catch block to handle the response/error:
try{
const response = await axios.post(url, params)
// handle response here
} catch (error) {
// handle error here
}

try...catch if a function throws error NodeJS

I'm trying to handle a function if it throws an error: create.js
function Apple() {
createDB() //function that saves into db
}
createDB.js
function createDB() {
const Info = new collection(data)
Info.save()
}
Suppose createDB function throws an error when required field in the db is not present. I want to handle such errors.
I tried:
function Apple() {
try{
createDB()//function that saves into db //if throws error go to catch
block
} catch{
function that handles error
}
}
and I also tried:
function createDB() {
return new Promise((resolve, reject) => {
if some condition met{
const Info = new collection(data)
Info.save()
}else{
reject(error)
}
})
}
But it still doesn't goes to the catch block. I'm relatively new to the topic so any suggestions will be really helpful. Basically I want to handle the errors if a function throws error, and it should go to catch block.
You are actually not following the correct syntax. Check out the sampe one:
try {
nonExistentFunction();
} catch (error) {
console.error(error);
// expected output: ReferenceError: nonExistentFunction is not defined
// Note - error messages will vary depending on browser
}
Your updated code with try-catch should follow the above syntax:
function Apple() {
try{
createDB()//function that saves into db //if throws error go to catch
block
} catch (error) {
function that handles error
// here you should log errors or use the logging lib
}
}
Also, if you are using promises, you can follow this approach:
function createDB() {
return new Promise((resolve, reject) => {
if (condition) {
const Info = new collection(data);
Info.save().then(data =>{ resolve(data)})
.catch(e => {console.error(e)}) // handle this promise also
}
else {
reject(error);
}
})
}
Also, you need to understand when to use try-catch block and when to use promises. The try, catch blocks are used to handle exceptions (a type of an error) when the code is synchronous. You should use Promises only for asynchronous functions and nothing else.
Use this sample piece of code
Within try block we write our code which we want to execute
If any error occur controller goes to catch block
In catch block we also receive error
try {
//Here write your code which you want to execute
return true
} catch (error) {
//if there is an any error controller will come into this block and show error
console.error(error);
return false
}

Throw Error with loop of await function

I'm struggling with a loop of async await function. I'm creating an API which POST a request to another API. I have to make a loop because users could insert many items at once in the database.
The API that I call rejects Parallel executions so I can't use Promise.all :/
In order to implement that service I made a function to insert one object :
const addValue = async (ID:number, cookie: string) => {
try {
const addValueBody = await addValueQuery(ID:number)
const header = { 'cookie': cookie, 'content-type': 'application/json' }
const fetchResult = fetch('http://api-to-call.xyz', { method: `POST`, headers: header, body: addValueBody })
const response = await fetchResult
const jsonData = await response.json()
return jsonData
} catch (e) {
throw Error(e.message)
}
}
And a function which will execute addValue inside a for loop :
const addMulti = async (values: any, cookie: string) => {
for (const item of values) {
await addValue(item.ID, cookie)
}
}
The problem is that when I call addMulti and if there is an Error I have a UnhandledPromiseRejectionWarning.
Also I tried to put de for ... in or await addValue inside a try catch but it doesn't catch the Error(s)
Hence, I have 2 questions :
How can I throw en Error if it occurs during the execution of the loop ?
Is it possible to break the loop if there is an error ?
Thanks for your help :)
How can I throw en Error if it occurs during the execution of the loop ? Is it possible to break the loop if there is an error ?
Your code does that already, by awaiting addValue. If addValue throws an error, since addMulti doesn't catch, it terminates addMulti as well.
The problem is that when I call addMulti and if there is an Error I have a UnhandledPromiseRejectionWarning.
The code you've shown is correct¹, the problem is that it appears you have no error handling on the call to addMulti. That code must either:
Handle errors from it (via try/catch in an async function if you don't want to allow it to propagate, or via the catch method if using the promise directly), or
Propagate the error to something that will handle it (by not catching it in an async function, or by returning the promise in a non-async function)
So for instance, if the call to addMulti is in a non-async function and if nothing calling that function will handle errors, you need to handle it at that stage:
addMulti(/*...*/)
.catch(error => {
// ...handle/report the error
});
If it's in an async function but nothing handles that async function's errors, then:
try {
await addMulti(/*...*/);
} catch (e) {
// ...handle/report the error
}
¹ ...other than it seems odd to catch e and then do throw Error(e.message); just let the error propagate.
When you get UnhandledPromiseRejection working with async functions, it almost surely means that you didn't catch the thrown error. In your case you could just wrap the whole loop in try{...} catch{...} block:
const addMulti = async (values: any, cookie: string) => {
try {
for (const item of values) {
await addValue(item.ID, cookie)
}
} catch(e) {
console.log('Error occured in async function')
}
}

Javascript fetch, catch runs forever

What happens: If I use fetch..catch and calls another function. In that next function if anything crashes. It will be caught in last catch. This will go on so if the next function crashes it will still be caught in the fetch..catch
What I want: When calling myExternalFunction() I want to 'disconnect' from the try..catch that fetch throws.
fetch('mystuff.url')
.then((data)=>{
myExternalFunction();
})
.catch((e)=>{
// all future errors will come here
})
myExternalFunction(){
// This error will be caught by fetch..catch
// we don't want that
crash();
}
Fiddler example to try it
You don't want to chain your catch to the then then, but keep them at the same level:
fetch(...).then(successCallback, failCallback)
Or:
const p = fetch(...);
p.then(successCallback);
p.catch(failCallback);
const p = Promise.resolve('foo');
p.then(() => { throw new Error('noooooo') });
p.catch(() => console.error('caught'));
The difference is that fetch().then().catch() will catch any error produced by either the fetch promise or the then promise; while the above two methods apply the failCallback only to the fetch promise.
When calling myExternalFunction() I want to 'disconnect' from the
try..catch that fetch throws.
Catch the exception of crash in myExternalFunction itself.
fetch('mystuff.url')
.then((data)=>{
myExternalFunction();
})
.catch((e)=>{
// all future errors will come here
})
function myExternalFunction(){
try
{
crash();
}
catch(e)
{
//do nothing
}
}
Or (if modifying external function is not possible) catch the same in then
fetch('mystuff.url')
.then((data)=>{
try
{
myExternalFunction();
}
catch(e)
{
//do nothing
}
})
.catch((e)=>{
// all future errors will come here
})
function myExternalFunction(){
crash();
}
If we don't want to wrap the 'external function' in try..catch (then we need to continue to wrap next call as well and so on. This issue can be noted when e.g. using react with redux thunk. How a fetch..catch captures errors happening somewhere else.
To completly break we need something else as setTimeout. Must be a better way for this.
fetch('mystuff.url')
.then((data)=>{
// this will break out so 'external function' doesn't get caught in catch.
setTimeout(myExternalFunction,1);
})
.catch((e)=>{
// only errors from the fetch
})
function myExternalFunction(){
crash(); // we are happy, it crashes without involving fetch
}
If you want to use catch with fetch I propose to use this solution.
fetch("http://httpstat.us/500")
.then(function(response) {
if (!response.ok) {
throw Error(response.status);
}
return response;
}).then(function(response) {
alert("ok");
}).catch(function(error) {
alert(error);
});

Categories

Resources