A fetch API request will only fail if there is a network or server error. So for example, if I execute the following code, assuming it went through the try
block without an error, I will have a valid populated res
.
try {
const res = await fetch('/createurl', {
method: 'POST',
body: 'testData',
headers: {
'Content-Type': 'application/json'
}
})
if (res.ok) {
alert('Resource created!')
} else {
alert('Error creating resource!')
}
flashResponseToUser(res)
} catch(e) {
alert('A server or network error occurred during the request!')
}
I am handling res
to show the users the necessary error
or success
message using the flashResponseToUser(res)
function. Since res.json()
returns a Promise
, flashResponseToUser
has to be an async function.
const flashResponseToUser = async(res) => {
const jsonRes = await res.json() // Get data from response
console.log(jsonRes)
}
I want to know:
- Why does
res.json()
return aPromise
since at this point the response has already been received by the client? - Under what conditions would the
Promise
returned byres.json()
fail? - Does the code within
flashResponseToUser(res)
also need to be wrapped within atry-catch
block since I am usingres.json()
?
A fetch API request will only fail if there is a network or server error. So for example, if I execute the following code, assuming it went through the try
block without an error, I will have a valid populated res
.
try {
const res = await fetch('/createurl', {
method: 'POST',
body: 'testData',
headers: {
'Content-Type': 'application/json'
}
})
if (res.ok) {
alert('Resource created!')
} else {
alert('Error creating resource!')
}
flashResponseToUser(res)
} catch(e) {
alert('A server or network error occurred during the request!')
}
I am handling res
to show the users the necessary error
or success
message using the flashResponseToUser(res)
function. Since res.json()
returns a Promise
, flashResponseToUser
has to be an async function.
const flashResponseToUser = async(res) => {
const jsonRes = await res.json() // Get data from response
console.log(jsonRes)
}
I want to know:
- Why does
res.json()
return aPromise
since at this point the response has already been received by the client? - Under what conditions would the
Promise
returned byres.json()
fail? - Does the code within
flashResponseToUser(res)
also need to be wrapped within atry-catch
block since I am usingres.json()
?
- developer.mozilla.org/en-US/docs/Web/API/Body this will be able help you with those questions. – sshanzel Commented Jan 14, 2020 at 7:16
- 1 @Siege21x I did read that but it still doesn't explain why res.json() returns a Promise instead of returned data directly. Also doesn't tell us under what conditions res.json() fails. – philosopher Commented Jan 14, 2020 at 7:19
- answer for first question. answer for second question. – SuleymanSah Commented Jan 14, 2020 at 7:31
1 Answer
Reset to default 20Why does res.json() return a Promise since at this point the response has already been received by the client?
fetch
returns a Response object. This indicates that the headers of the response have been received, but does not necessarily mean that the whole response has been received - imagine, for example, when you load a huge page. It's not exactly the same thing, but you'll receive the headers and the browser will start to load the response even though there's still more to download. The Response object provides the headers and a way to handle still-incoming data.
Under what conditions would the Promise returned by res.json() fail?
It might fail if the response wasn't in proper JSON format. For example, if the plain text of the response was Internal Server Error
, which isn't JSON. Here's an example:
(async () => {
const response = await fetch('data:,Internal%20Server%20Error');
console.log('got response');
try {
await response.json();
} catch(e) {
console.log('error:', e.message);
}
})();
Does the code within flashResponseToUser(res) also need to be wrapped within a try-catch block since I am using res.json()?
If you wanted to be perfectly safe, yes. But, in most situations, it's easiest just to catch in one place, where you can handle the error. Instead of handling possible errors at every step of the process, you might handle the error just once, in the consumer, eg:
const getInfo = async () => {
const res = await fetch('/createurl', {
method: 'POST',
body: 'testData',
headers: {
'Content-Type': 'application/json'
}
})
if (!res.ok) {
throw new Error(res.status);
}
return res.json();
};
getInfo()
.then(flashResponseToUser)
.catch(() => {
alert('A server or network error occurred during the request!')
})
(assuming that flashResponseToUser
will never throw, if provided with an expected object. If flashResponseToUser
might throw anyway, you can separate out the .catch
es to distinguish network errors from other runtime errors)