fetch-plus icon indicating copy to clipboard operation
fetch-plus copied to clipboard

Problems reading json() when status > 400

Open nuclearspike opened this issue 8 years ago • 2 comments

I do a post to a server and receive a 422 error, the body of the response contains a json object with what validations it failed. However, the docs for fetch indicate that the body of the response hasn't been read at the time of the promise rejection. The body is a ReadableByteStream and the only code I've found to read that is this:

var decoder = new TextDecoder();
var reader = response.body.getReader();

// read() returns a promise that resolves
// when a value has been received
reader.read().then(function processResult(result) {
  if (result.done) return;
  console.log(
    decoder.decode(result.value, {stream: true})
  );

  // Read some more, and recall this function
  return reader.read().then(processResult);
});

The JsonPlus middleware doesn't handle it either. What is the correct way to be able to read the response.json() on a rejected fetch?

Code that may need to change in the fetch-plus source: http://stackoverflow.com/questions/29473426/fetch-reject-promise-with-json-error-object

Where I found the code to read the body: https://jakearchibald.com/2016/streams-ftw/

nuclearspike avatar Jun 08 '16 10:06 nuclearspike

The correct way is to add a middleware with an error handler that returns the rejected value so the promise chain is effectively recovered.

apiClient.addMiddleware((request) => {
    return {
        error: (response) => {
            if (typeof response.json === "function") {  // alternatively check the http status code
                return response.json(); // return rejected value to recover promise chain
            }

            throw response; // fatal error
        }
    };
}));

Should this behavior be (configurable) in the fetch-plus-json you think?

RickWong avatar Jun 08 '16 10:06 RickWong

I'd figured out something similar just moments before I saw your message:

error: response => {
      if (response.status == 422) {
        return response.json().then(json => Promise.reject({response, json}))
      } else {
        ...
      }
    }

I didn't get it to work unless I have the Promise.reject() though.

To more closely match the pattern in fetch-plus-json, it should redefine the body property?

Yes, I do think this should be included in the fetch-plus-json as it's a common issue, I'd think.

nuclearspike avatar Jun 08 '16 11:06 nuclearspike