-2

I'm trying to get data from backend server usin this fetch function:

 let users = []
  const fetchUsers = () => {
    fetch(baseUrl + "/users/", {
      method: "GET",
    })
      .then((res) => res.json())
      .then((data) => (resJSON = data))
      .then((resJSON) => {
          users = resJSON;
      })
      .catch((err) => {
        console.log("error in json", err);
        users = [];

      });
  };

But I get

error in json ReferenceError: resJSON is not defined

error happens in this line: .then((data) => (resJSON = data))

The wierd thing is that I see in the backend that the json is created. Also I'm using very similar fetch request for POST data on another endpoint without any issues. So I'm wondering what could be wrong here?

dafreako
  • 31
  • 4
  • try remove the last then and set users = data – cmgchess Feb 12 '22 at 11:19
  • Why do you think that `.then((data) => (resJSON = data))` is required? just remove that line. – t.niese Feb 12 '22 at 11:22
  • When I use `.then((data) => (users = data))` directly, I get an `[object Object]` instead of the resulting json. – dafreako Feb 12 '22 at 11:22
  • `I get an [object Object] instead of the resulting json`, the line `res.json()` parses the json and returns a Promise that fulfills with that parsed result (or rejects in case of a parsing error). In the shown code there is nothing that would emit `[object Object]`, but if `data` is an object then the request to `/users` returns an as json encoded object. – t.niese Feb 12 '22 at 11:28
  • 1
    @T.J.Crowder It is a much cleaner way and resolves the problem. Thanks for the tip. I really got lost in the `.then(` jungle. – dafreako Feb 12 '22 at 11:36
  • `[{234 534 bob man 1070 avatar.jpg germany false}]` is not a valid json. What do you receive from your server if you request `/users` (either directly in the browser or check the result in the developer tools in the network tab) – t.niese Feb 12 '22 at 11:38

2 Answers2

1

The problem is that resJSON = data is assigning to an identifier that isn't declared anywhere. Apparently your code is running in strict mode (good!), so assigning to an undeclared identifier is an error.

But there's no need for resJSON, it doesn't do anything useful in that code. You could combine the two then handlers and do users = data. But, that's generally poor practice, because you're setting yourself up for this problem where you try to use users before it's filled in. (Your code is also falling prey to the fetch API footgun I describe in this post on my anemic old blog: You need to check ok before you call json().)

But fundamentally, having fetchUsers directly assign to a users variable declared outside of it is asking for trouble. Instead, have fetchUsers return a promise of the users array. Here in 2022 you can do that with an async function:

const fetchUsers = async () => {
    const response = await fetch(baseUrl + "/users/", {
        method: "GET",
    });
    if (!response.ok) {
        throw new Error(`HTTP error ${response.status}`);
    }
    return await response.json();
};

(If you want to hide errors from the calling code (which is poor practice), wrap it in a try/catch and return an empty array from the catch.)

Then have the code that needs to fill in users do let users = await fetchUser(); (note that that code will also need to be in a async function, or at the top level of a module).

If for some reason you can't use an async function, you can do it the old way:

const fetchUsers = () => {
    return fetch(baseUrl + "/users/", {
        method: "GET",
    })
    .then(response => {
        if (!response.ok) {
            throw new Error(`HTTP error ${response.status}`);
        }
        return response.json();
    });
};
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

You are having an assignment in your return statement. Additionally, this assignment is scoped to the current callback, so in the next .then block resJSON is not available. It is also not required to try to do an extra assignment.

let users = []
fetch(/* ... */)
   .then((res) => {
        // res is the raw response.
        // res.json returns a new promise
        // that when sucefully fulfilled, 
        // will return the decoded body
        return res.json()
    })
   .then((data) => {
     // data refers to the json decoded 
     // bytes of the response body
     // assign it directly to user
     users = data
   })
   .catch(console.warn)

This may be still problematic, as you never know when the users are assigned or not. Depending on your code, you should shift additional work to the callback itself.

const useUserdata = (users) => 
    console.log("do something with the user", users)

fetch(/* ... */)
   .then(raw => raw.json())
   .then(useUserdata)
   .catch(console.warn)
The Fool
  • 16,715
  • 5
  • 52
  • 86