Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

In JS fetch API promise style, how to get the raw body when the json() function failed

I know this can be solved by writing all codes to async-await style, then can simply write let text = await res.text(); then try catch the JSON.parse(text) and then do decision.
But here I just want to know if there is any way we can achieve that in .then/.catch style.

Consider the below code:

async function test() {
  try {
    let n = await fetch("https://stackoverflow.com")
    .then(res => {
      return res.json()
    })
    .then(data => data.results.length)
    .catch(e => {
      console.error("Catch 2", e)
    })
  }
  catch (e) {
    console.error("Catch 3", e)
  }
}

if we execute this function in the browser devtools(F12) with await test(), then there will be an error catch by the "Catch 2" clause. But in the error detail we can only see some logs like JSON parse error.
We cannot see the full text of the response body.
Is there any way that can get the text when the JSON parsing failed?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

Your best bet is to look at the response in your devtools’ network tab. That will show you the full response.

But if you want to do it in code, you can separate reading the response from parsing it by using the text method instead of the json method, then parsing the text yourself.

The parsing error may be down to the fact you aren’t checking for HTTP success. As I noted on my old anemic blog here, fetch only rejects its promise on network errors, not HTTP errors (like 404, 500, etc.). To check for HTTP success, look at the ok or status properties.

Here’s the minimal-changes version separating reading the response from parsing it, and checking for HTTP success before reading it at all:

async function test() {
    try {
        let n = await fetch("https://stackoverflow.com")
            .then((res) => {
                if (!res.ok) {                                      // ***
                    throw new Error(`HTTP error ${res.status}`);    // ***
                }                                                   // ***
                return res.text(); // ***
            })
            .then((text) => {
                // *** you can look at `text` here in a debugger, or
                // *** log it, save it, etc., before parsing below
                // *** (which might throw an error)
                try {
                    const data = JSON.parse(text); // ***
                    return data.results.length;
                } catch (error) {
                    console.error("Parsing error", e);
                    console.error("Text we were parsing:", text);
                }
            })
            .catch((e) => {
                console.error("Catch 2", e);
            });
        // ...do something with `n`...
    } catch (e) {
        console.error("Catch 3", e);
    }
}

But a couple of things there:

  1. I wouldn’t mix async/await with explicit promise callbacks like that.

  2. With that and with your original code, errors will result in n receive the value undefined, because the catch handlers (and my new try/catch block in the then handler) don’t return anything.

Instead:

async function test() {
    try {
        const res = await fetch("https://stackoverflow.com");
        if (!res.ok) {
            throw new Error(`HTTP error ${res.status}`);
        }
        const text = await res.text();
        // *** you can look at `text` here in a debugger, or
        // *** log it, save it, etc., before parsing below
        // *** (which might throw an error)
        try {
            const data = JSON.parse(text);
            const n = data.results.length;
            // ...do something with `n`...
        } catch (error) {
            console.error("Parsing error", e);
            console.error("Text we were parsing:", text);
        }
    } catch (e) {
        console.error("Catch 3", e);
    }
}

Or if you want to respond differently to the parsing error, wrap that bit in a try/catch, etc.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading