Search code examples
javascriptpromisefetchtypeerror

Can't call fetch api multiple times


I want to call this api multiple times in my project and when I am calling it , It continues giving an error which is

TypeError: Failed to execute 'json' on 'Response': body stream already read at main.js:Line number

My Code is as Follows

let thisIsUrl = 'https://api.covid19api.com/summary';
let a = fetch(thisIsUrl)
a.then((data) => {
    return data.json()
}).then((apidata) => {
    console.log(apidata)
    return apidata
}).catch((error) => {
    console.log(error)
})


a.then((fetchdata) => {
    return fetchdata.json()
}).then((readingData) => {
    console.log(readingData)
}).catch((err) => {
    console.log(err)
})

Solution

  • You're not calling fetch multiple times. You're calling it once, and then trying to read the response body multiple times. That's why the error says you're trying to read the body when the stream is already closed — it was closed when you were done reading it the first time.

    If you want to use the data twice, store it somewhere and use it twice.

    let thisIsUrl = 'https://api.covid19api.com/summary';
    let a = fetch(thisIsUrl)
    a.then((data) => {
        return data.json()
    }).then((apidata) => {
        // **************** Use it twice here
    }).catch((error) => {
        console.log(error)
    })
    

    If you want to fetch it again because it may have been updated, call fetch again:

    let thisIsUrl = 'https://api.covid19api.com/summary';
    fetch(thisIsUrl)
    .then((data) => {
        return data.json();
    }).then((apidata) => {
        console.log(apidata);
        return apidata;
    }).catch((error) => {
        console.log(error);
    });
    
    
    // Presumably this is later (in time), not immediately after the above
    fetch(thisIsUrl)
    .then((fetchdata) => {
        return fetchdata.json();
    }).then((readingData) => {
        console.log(readingData);
    }).catch((err) => {
        console.log(err);
    });
    

    Finally, this seems unlikely, but if you really want to fetch it once and use that one result in multiple places via the promise chain, keep the promise from then rather than the promise from fetch:

    let thisIsUrl = 'https://api.covid19api.com/summary';
    let a = fetch(thisIsUrl)
    .then((data) => {
        return data.json()
    });
    a.then((apidata) => {
        // ***** Use it here
    }).catch((error) => {
        console.log(error)
    })
    
    a.then((readingData) => {
        // ***** And then again here
    }).catch((err) => {
        console.log(err);
    });
    

    Side note: Your code is falling prey to a footgun in the fetch API; I've written about it in this blog post. fetch only rejects its promise on network errors, not HTTP errors. You have to check for those yourself in the first fulfillment handler, by checking for ok on the response object:

    fetch("/your/resource")
    .then(response => {
        if (!response.ok) {
            throw new Error("HTTP error " + response.status); // Or better, use an Error subclass
        }
        return response.json();
    })
    // ...