Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fetch API: Can 'await res.json()' fail after a completed request?

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:

  1. Why does res.json() return a Promise since at this point the response has already been received by the client?
  2. Under what conditions would the Promise returned by res.json() fail?
  3. Does the code within flashResponseToUser(res) also need to be wrapped within a try-catch block since I am using res.json()?
like image 375
philosopher Avatar asked Jan 14 '20 07:01

philosopher


People also ask

How do I use async await fetch api?

Using async/awaitYou start by specifying the caller function as async and then use await to handle the promise. Because of the await keyword, the asynchronous function pauses until the promise is resolved. The Response object is assigned to response once the request completes.

Does json need await response?

json() is a method on the Response object that lets you extract a JSON object from the response. The method returns a promise, so you have to wait for the JSON: await response.

Is Res json async?

Since res. json() returns a Promise , flashResponseToUser has to be an async function.

What is json () in fetch?

To get JSON from the server using the Fetch API, you can use the response. json() method. The response. json() method reads the data returned by the server and returns a promise that resolves with a JSON object. If you are expecting a text, call the response.


Video Answer


1 Answers

Why 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 .catches to distinguish network errors from other runtime errors)

like image 102
CertainPerformance Avatar answered Oct 27 '22 20:10

CertainPerformance