Currently, I was taking a course:Front-End Web Development with React in coursera, and I was stuck at a point where the instructor was showing how to fetch data using cross-fetch. Here he was showing
export const fetchDishes = () => (dispatch) => {
return fetch(baseUrl + 'dishes')
.then(
(response) => {
if (response.ok) {
return response;
} else {
var error = new Error(
'Error ' + response.status + ': ' + response.statusText
);
error.response = response;
throw error;
}
},
//manually handle error if the server didn't response
(error) => {
var errmess = new Error(error.message);
throw errmess;
}
)
.then((response) => response.json())
.then((dishes) => dispatch(addDishes(dishes)));
.catch(error => dispatch(dishesFailed(error.message)));
};
But my ESLint showing me error and suggest to use try...catch block.
image
But I was wondering why this error occurs even though the instructor write it as above and run the application perfectly? I have no idea how to convert this code into a try...catch block.
#erik_m give a solution but I did get that is semicolon mean terminate the promise chain? And one more thing which temp me that the instructor didn't import fetch (like import fetch from 'cross-fetch')then how my application is using fetch? He just showed to do yarn add cross-fetch#2.1.0 Did fetch is inherited by default with react application?
You are terminating the call one line above the catch.
.then((response) => response.json())
.then((dishes) => dispatch(addDishes(dishes)));
.catch(error => dispatch(dishesFailed(error.message)));
on the line right above the .catch, remove the semicolon, and the paren. Your catch is not properly part of your then statement.
Edit: Can you try to replace the last three lines with this? You have your parens and semi colons in the wrong place. So the program thinks you are ending your promise after the second then, so it is not recognizing the "catch" portion.
.then((response) => response.json())
.then((dishes) => dispatch(addDishes(dishes))
.catch(error => dispatch(dishesFailed(error.message))));
Related
This question already has answers here:
fetch: Reject promise with JSON error object
(5 answers)
Closed last year.
In a locally run Node.js script, this works when status is 200:
// module file
import fetch from "node-fetch";
export const getJSON = () => {
const url = 'https://api.somesite.com/api/v0/etc';
const options = {method: 'GET', headers: {Accept: 'application/json'}};
const request = fetch(url, options)
.then(response => response.json())
.catch(err => console.log("somesite:", err));
return Promise.resolve(request);
};
// execution file
import { getJSON } from './libs/api_requests.mjs';
console.log("func call", await getJSON());
But the fetch also works without triggering the .catch logic when the response status is 4xx or 5xx (see for example this answer).
Execution doesn't break and I actually receive an error message when the function is called as if that would be the correct, normal result - as the output of response.json().
This message is in plain English, something like "error: 'Incorrect path. Please check https://www.somesite.com/api/'".
I would like to preserve/display this error message, only I would like to catch it within the function getJSON in the module file, instead of having to wrap some logic around it at the destination, potentially repeating the same code multiple times everywhere the function is called, instead of dealing with the issue just once at the source.
So I modified the .then clause like this, which also works:
.then(response => { if (response.ok) { // .ok should be status 200 only, I suppose
return response.json();
} else { throw new Error(response.status) }
This now triggers the .catch clause as intended, displaying "Error: 404 [etc]". Except what I would like to throw is the original error message "Incorrect path [etc]" and that I could not do. I tried
.then(response => { if (response.ok) {
return response.json();
} else { throw new Error(response.json()) } // somesite: Error: [object Promise]
.then(response => { if (response.ok) {
return response.json()
} else { throw new Error(Promise.resolve(response.json())) } // somesite: Error: [object Promise]
.then(response => { if (response.ok) {
return response.json()
} else { throw new Error(return response.json()) } // SyntaxError: Unexpected token 'return'
.then(response => { if (response.ok) {
return response.json();
} else { throw new Error(Promise.resolve(request)) } // somesite: Error: [object Promise]
I guess I need to resolve the response.json() promise as if all was ok, but how to do that?
I also had a look at the request object with console.dir(request, { depth: null }) to see if I could extract the error message from there, but I couldn't find it and the object still contained many unexpanded elements like [Function: onerror] or [Function: onclose] for example.
Try response.text() instead of response.json() when the status code is 400 or 500.
In my experience, the error messages are typically returned by the text callback.
See this answer to a similar question.
Edit:
Added the following code, suggested by OP.
.then((response) => {
if (response.ok) {
return response.json();
}
else {
return response.text()
.then((text) => {
throw(text);
// if the error is an object and you just want to display some elements:
throw(JSON.parse(text));
});
}
})
.catch((err) => {
// in case you want to log the error
console.log("somesite: ", err));
return new Error("somesite: " + err);
});
I'm trying to load bunch of text files using multiple fetch requests via Promise.all. Here's how it looks:
////////////////////////////////////////
const loadTextFiles = (allUrls, textUrls) => {
const requests = textUrls.map(url => fetch(url));
return Promise.all(requests)
.then(responses => Promise.all(
responses.map(response => response.text())
))
.then(texts => texts.forEach(
(text, i) => allUrls[textUrls[i]] = text
))
.catch(err => {
// log("HERE");
throw exception("networkLoader",
"loadTextFiles",
`error in loadTextFiles: ${err.toString()}`);
});
};
allUrls and textUrls are two arrays that contain the urls of all resources (files with any extension) and text resources (files with .txt extension), respectively. In fact, textUrls is constructed from allUrls (never mind why or how). The results are stored inside the allUrls array. For example, if allUrls = [ "image.png", "essay.txt" ] , then textUrls = [ "essay.txt" ] . Now, if I call loadTextFiles:
await loadTextFiles(allUrls, textUrls);
I will get access to the contents of "essay.txt" by accessing allUrls["essay.txt"]. Things are okay so long as all text files exist and can be retrieved.
The problem is, despite the fact that I have written a catch to detect problems in Promise.all, it doesn't work. For instance, if I request fileThatDoesNotExist.txt I get a 404 (Not Found) in the browser console but my code inside catch doesn't run. I tested it even with a custom log function which also doesn't run. I'd like to catch the error and re-throw it. How do I do that?
Edit: When I said "I'd like to catch the error" I meant that I want to get notified of 404 error and throw an exception (in this case a custom exception object)
This question can be solved in the following way:
const loadTextFiles = (allUrls, textUrls) => {
const requests = textUrls.map(url => fetch(url));
return Promise.all(requests)
.then(responses => Promise.all(
responses.map(response => {
if (response.ok) {
return response.text();
}
throw exception("networkLoader",
"loadTextFiles",
`couldn't load ${response.url}`);
})
))
.then(texts => texts.forEach(
(text, i) => allUrls[textUrls[i]] = text
))
.catch(err => {
if (exception.isException(err)) {
throw err;
}
throw exception("networkLoader",
"loadTextFiles",
`error: ${err.toString()}`);
});
};
We test each response returned by fetch by checking its ok property, and if this property is false, then an exception is thrown.
I'm pretty new on React and I'm learning this language nowadays.
For this purpose I'm building a test project on which I try to encounter the main classical issues and looking to solve it.
For most of React developpers, there are no difficulties in following code but I will give a few details for better comprenhension.
I have a portion of javascript code that is returning a list of articles from a Symfony Backend API only if user is authorized for getting it (Authorization via JWT will be done later). A getArticles function returns a Promise that tries to get the articles from the Symfony backend inside a try {} catch (error) {} block.
Voluntarily, Authorization token is not send to trigger an error in the query.
As the axios.get is located inside a try {} catch (error) {} block, I am surprised that an error appears in the console for the request. It doesn't impact the behavior but it is not very clean to have these errors in the console.
My question(s) :
Why an error appears in the console while the code is inside a try/catch ? To get a cleaner app behavior, is there a way to avoid having this error in the console ? I have found other React try/catch issues but I didn't deduct the similarity with my issue. Am I missing something ?
Thanks in advance ;-)
I am aware that my code could be refactored, do not hesitate to suggest any good practice
componentDidMount(){
/*To be prepared to attach JWT token*/
axios.interceptors.request.use(req => {
return req;
});
const getArticles = async() => { return new Promise( (resolve, reject)=> {
try{
const data = axios.get('https://xxxxx/api/articles');
resolve(data);
} catch (err) {
reject(err);
}
});
}
getArticles().then(res => {
const articles = res.data.data.items;
this.setState( {errorOnArticlesLoading:false, articles: articles } );
})
.catch(error => {
this.setState( {errorOnArticlesLoading:true} );
});
}
You can try in this way and Async functions itself returns a promise, you don't need to return a new Promise manually.
async componentDidMount() {
try {
/*To be prepared to attach JWT token*/
axios.interceptors.request.use(req => req);
const getArticles = async () => {
try {
const data = axios.get('https://xxxxx/api/articles');
this.setState({ errorOnArticlesLoading: false, articles: data.data.items });
} catch (err) {
this.setState( {errorOnArticlesLoading:true} );
}
};
await getArticles()
} catch(err) {
console.log('Handled root error')
}
}
It seems that there are no solutions to avoid the 401 http error code in the console because it it printed by Chrome itself: See discussion here. So the following code cannot avoid the 401 error status to be printed in the console.
componentDidMount(){
/*To be prepared to attach JWT token*/
axios.interceptors.request.use(req => {
return req;
});
const getArticles = async() => {
const data = await axios.get('https://xxxx/api/articles');
return data;
}
getArticles().then(res => {
const articles = res.data.data.items;
this.setState( {errorOnArticlesLoading:false, articles: articles } );
})
.catch(error => {
this.setState( {errorOnArticlesLoading:true} );
});
}
This question already has an answer here:
Google Cloud Functions - warning Avoid nesting promises promise/no-nesting
(1 answer)
Closed 3 years ago.
NOTE: this question is mainly about error handling, and if this is an ok approach, not about nesting promises, please read before closing
Since there are currently no error codes for services like firestore and firebase database, i'm using a system to know where the function failed and to handle error accordingly, simplified version below:
exports.doStuff = functions.https.onCall((data, context) => {
return [promise doing stuff goes here].catch(error => { throw new Error('ERROR0') })
.then(result => {
return [promise doing stuff goes here, needs result of previous promise]
.catch(error => { throw new Error('ERROR1') })
})
.then(result => {
return [promise doing stuff goes here, needs result of previous promise]
.catch(error => { throw new Error('ERROR2') })
})
.then(result => {
//inform client function successful
return {
success: true
}
})
.catch(error => {
if (error !== null) {
switch (error.message) {
case 'ERROR0':
//do stuff
throw new functions.https.HttpsError('unknown', 'ERROR0');
case 'ERROR1':
//do stuff
throw new functions.https.HttpsError('unknown', 'ERROR1');
case 'ERROR2':
//do stuff
throw new functions.https.HttpsError('unknown', 'ERROR2');
default:
console.error('uncaught error: ', error);
throw error;
}
}
});
});
the thing is, for each .catch() inside each returned promise, i'm getting the following warning: warning Avoid nesting promises
so my question is, is there a better way to handle errors?
Ultimately it's a style recommendation to prevent bizarre and hard to recognise errors. Most of the time a rewrite can eliminate the warning. As an example, you could rewrite your code as the following whilst retaining the same functionality.
exports.doStuff = functions.https.onCall(async (data, context) => {
const result1 = await [promise doing stuff goes here]
.catch(error => {
throw new functions.https.HttpsError('unknown', 'ERROR0', { message: error.message } )
});
const result2 = await [promise based on result1 goes here]
.catch(error => {
throw new functions.https.HttpsError('unknown', 'ERROR1', { message: error.message } )
});
const result3 = await [promise based on result1/result2 goes here]
.catch(error => {
throw new functions.https.HttpsError('unknown', 'ERROR2', { message: error.message } )
});
return {
success: true
};
});
Lastly, rather than using unknown everywhere, you could use one of several possible values for the first argument whilst passing in whatever supporting information you need as the third argument (as shown above where I pass through the original error message).
I recently have learned something about fetch() and promise, and now I need to use it in project. Here I have a fetch() function, which works very well, but I think, it must catch an error. So, what is the best way to catch error in fetch() functions? And i need to catch them in both then()?
Here some code:
const endpoint = 'http://localhost:3030/api/hotels';
const promise = fetch(endpoint)
.then(res => res.json(), err => {
console.log(err);
})
.then(parseRooms, err => {
console.log(err);
})
Thank you !
Use the fact that promise handlers chain together. Each call to then or catch creates a new promise, which is chained to the previous one.
So in your case:
const promise = fetch(endpoint)
.then(res => res.json())
.then(parseRooms)
.catch(error => {
// Do something useful with the error
});
I'm assuming there that parseRooms throws an error if there's a problem with the structure it receives.
You probably want to check res.ok in there, too, since fetch only fails if there was a network error, not if there was an HTTP error such as a 404:
const promise = fetch(endpoint)
.then(res => {
if (!res.ok) {
throw new Error(); // Will take you to the `catch` below
}
return res.json();
})
.then(parseRooms)
.catch(error => {
// Do something useful with the error
});