Mathias Gielen
Mathias Gielen

Reputation: 91

Fetch API - GET request with status 200 returning an empty body

I got a really weird problem. This javascript code is supposed to fetch an object from the back-end with a GET-request. The header I receive has status 200, but the body seems to be empty.

function GetAssignment() {
    assignment = fetch(GetAssignmentURL,
        {
            method: 'GET',
            headers: {
                'Accept': 'application/json',
                
            }
        })
        .then((response) => {
            if (response.status == 200) {
                console.log(response);
                return response.json();
            }
            else
            {
                throw `error with status ${response.status}`;
            }
        })
        
        .catch((exception) => {
            console.log(exception);
        }); 
}

Response: https://i.sstatic.net/B3pfo.png

Now, I tried the same thing with Postman, and it works just fine here. (I've checked the URL to call the back-end and it's totally the same in Postman as in Javascript, so the error doesn't lie there.) Result: https://i.sstatic.net/H6Pnm.png

So, I'm wondering what's wrong with my Javascript code. I debugged the back-end, and when I'm calling with Javascript it does return an object like how it should. I've always done GET-requests this way, but now all of a sudden, the response body is being obstructed in the front-end of my application.

Has anyone ever had the same problem?

Upvotes: 5

Views: 13817

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1075239

Nothing in the code you've shown is actually using the body. You're logging response before you tell it to read the body, and your assignment variable just has the promise from fetch, it doesn't try to do anything with it.

To see the body, you need to look at the fulfillment value of the promise from json (which will do two things: 1. read the body, and 2. parse it from JSON).

For instance:

function GetAssignment() {
    fetch(GetAssignmentURL,                 // *** No `assignment =` on this line
        {
            method: 'GET',
            headers: {
                'Accept': 'application/json',
                
            }
        })
        .then((response) => {
            if (response.status == 200) {   // *** This can be just `if (response.ok) {`
                console.log(response);      // *** This is premature
                return response.json();
            }
            else
            {
                throw `error with status ${response.status}`;
            }
        })
        .then(assignment => {               // ***
            // ...use `assignment` here...  // ***
        })                                  // ***
        .catch((exception) => {
            console.log(exception);
        }); 
}

But: If the goal is to communicate assignment to the code calling the function, you need to return the promise chain, like this:

function GetAssignment() {
    return fetch(GetAssignmentURL,
        {
            method: 'GET',
            headers: {
                'Accept': 'application/json',
                
            }
        })
        .then((response) => {
            if (response.status == 200) {   // *** This can be just `if (response.ok) {`
                console.log(response);      // *** This is premature
                return response.json();
            }
            else
            {
                throw `error with status ${response.status}`;
            }
        });
}

Code using it would use it like this:

GetAssignment()
.then(assignment => {
    // ...use `assignment` here...
})
.catch(error => {
    // handle/report error
});

Side note: If GetAssignment isn't meant to be called with new, the overwhelmingly-common convention in JavaScript is that it would start with a lowercase letter: getAssignment.


And just to put it out there, since ES2018 was a couple of years ago now, in modern environments (or if you're transpiling) you can use async functions, which make it possible to write your logic without worrying as much about timing. async functions return promises, and let you use await to pause your logic while waiting for a promise to settle:

async function getAssignment() {
    const response = await fetch(GetAssignmentURL, {
        method: 'GET',
        headers: {
            'Accept': 'application/json',
            
        }
    });
    if (!response.ok) {
        throw `error with status ${response.status}`;
    }
    return response.json();
}

In the above, the call to fetch happens synchronously, but then the function suspends itself waiting for the result and returns a promise. The promise it returns will settle based on what happens to the promise(s) it awaits. Eventually, all being well, its promise is fulfilled with the value you return (or in the case of the above, the fulfillment value response.json() provides when it settles).

You'd use it like this (inside another async function):

const assignment = await getAssignment();
// ...use `assignment` here...

(If there's an error, the async function the code above is in will reject the promise)

Upvotes: 4

Related Questions