skip to Main Content

I am working on a blog app for my internship, this is my second project in ExpressJS and I have encountered a problem I did not in the previous one (a library management system project I made for college).

const register = asyncHandler(async (req, res) => {
  try {
    const { email, username, name, password } = req.body;
    if (!email || !username || !name || !password) {
      res.status(400).json({ message: "please enter credentials" });
      throw new Error();
    }

    const checkEmail = await User.findOne(email);
    if (checkEmail) {
      res.status(400).json({ message: "email already registered" });
      throw new Error();
    }

    const checkUsername = await User.findOne({ username });
    if (checkUsername) {
      res.status(400).json({ message: "username already exists" });
      throw new Error();
    }

    const salt = await bcrypt.genSalt(69);
    const hashedPassword = await bcrypt.hash(password, salt);

    const user = User.create({
      email,
      username,
      name,
      hashedPassword,
    });

    res.status(200).json(user);
  } catch (error) {
    res.status(500).json({ message: "something happened, try again" });
    throw new Error();
  }
});

When I try to test this controller function, it runs the first response statement regardless of whether I enter the credentials or not (I am testing using postman), the terminal shows the following error

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

I am literally following the same method as I did in my first project where I did not encounter this error.

I tried looking for solutions on YouTube, the solution suggested in most of the videos was to return the response statement but I can’t use return since I cannot do "throw new Error" after that.

2

Answers


  1. Instead of throwing an error after sending the response, you can return from the function to prevent any further code execution.

    const register = asyncHandler(async (req, res) => {
      try {
        const { email, username, name, password } = req.body;
        if (!email || !username || !name || !password) {
          res.status(400).json({ message: "please enter credentials" });
          return;  // Stop further execution
        }
    
        const checkEmail = await User.findOne({ email });  // Corrected the query object
        if (checkEmail) {
          res.status(400).json({ message: "email already registered" });
          return;  // Stop further execution
        }
    
        const checkUsername = await User.findOne({ username });
        if (checkUsername) {
          res.status(400).json({ message: "username already exists" });
          return;  // Stop further execution
        }
    
        const salt = await bcrypt.genSalt(10);  // Usually, 10 is sufficient for salt rounds
        const hashedPassword = await bcrypt.hash(password, salt);
    
        const user = await User.create({  // Await User.create to wait for completion
          email,
          username,
          name,
          password: hashedPassword,  // Use 'password' as the field name
        });
    
        res.status(200).json(user);
      } catch (error) {
        res.status(500).json({ message: "something happened, try again" });
      }
    });
    
    Login or Signup to reply.
  2. If you have a condition and you want to exit early you would use return because calling res.send(),res.json() more than once will throw an error.
    make sure that your response object returns data

    Instead of

      res.status(400).json({ message: "please enter credentials" });
    

    Do this

       return res.status(400).json({ message: "please enter credentials"});
    

    Will return response and not run the rest of the code after next line

    but For final response you don’t need to user return

    res.status(200).json(user);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search