[Fixed] Why it only returns the first id from my mock up database?

Issue

In short I am trying to create a simple api that would return the user with the matching id. I use postman to send requests to my localhost created using node.js with express. It works fine when I request the first user but throws in an error when requesting "John". I am coding along a udemy course and can’t figure out what the issue is other than the material is outdated. The error is "Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client"

 users: [
    {
      id: "123",
      name: "Sally",
      email: "[email protected]",
      password: "bananas",
      entries: 0,
      joined: new Date(),
    },
    {
      id: "124",
      name: "John",
      email: "[email protected]",
      password: "apples",
      entries: 0,
      joined: new Date(),
    },
  ],
};
 
 app.get("/profile/:id", (req, res) => {
  const { id } = req.params;
  let found = false;
  database.users.forEach((user) => {
    if (user.id === id) {
      found = true;
      return res.json(user);
    }
    if (!found) {
      res.json("User not found");
    }
  });
});

Solution

From the MDN Web Docs:

There is no way to stop or break a forEach() loop other than by throwing an exception. If you need such behavior, the forEach() method is the wrong tool.

Early termination may be accomplished with:

  • A simple loop
  • A forof
    loop
  • [Array.prototype.every()][every]
  • [Array.prototype.some()][some]
  • [Array.prototype.find()][find]
  • [Array.prototype.findIndex()][findIndex]

This means that your loop will run through all elements and in fact call res.json multiple times resulting in the ERR_HTTP_HEADERS_SENT error . There are many ways to fix this, here’s an one example:

app.get("/profile/:id", (req, res) => {
    const {id} = req.params;      
    for (const user of database.users) {
        if (user.id === id) {
            return res.json(user);
        }
    }
    res.json("User not found");
});

Leave a Reply

(*) Required, Your email will not be published