Tycholiz
Tycholiz

Reputation: 1200

Cannot call res.send() within promise

I am refactoring my code from using callbacks. Of course, everything in this first solution works as expected:

        const newUser = new User({
            email,
            password,
        })

        User.exists({ email }, (err, userExists) => {
            if (err) {
                return next(err)
            }
            if (userExists) {
                return res.status(400).send("A user with that email already exists")
            }
            newUser.save()
                .then(result => console.log('new user successfully registered!:', result))
                .catch(err => {
                    console.error('Cannot save user: ', err)
                })

            var profile = _.pick(req.body, 'email', 'password', 'extra')

            res.status(201).send({
                id_token: createIdToken(profile),
                access_token: createAccessToken()
            })
        })

Here is after the refactor:

        User.exists({ email })
            .then(userExists => {
                if (userExists) {
                    res.status(400).send("A user with that email already exists")
                }
            })
            .then(() => {
                const newUser = new User({
                    email,
                    password,
                })
                return newUser
            })
            .then(newUser => {
                console.log('newUser: ', newUser);
                return newUser.save()
            })
            .then(result => console.log('new user successfully registered!:', result))
            .catch(err => {
                console.error('Cannot save user: ', err)
                return next(err)
            })

However, this does not work. I've isolated down where in the promise chain the error occurs, and it happens when I try to send the response back to the client res.send

The error I get is: C

cannot save user: Error: Can't set headers after they are sent. at validateHeader (_http_outgoing.js:491:11) at ServerResponse.setHeader (_http_outgoing.js:498:3) at ServerResponse.header (/home/kyle/programming/projects/never-forget/server/node_modules/express/lib/response.js:771:10) at ServerResponse.send (/home/kyle/programming/projects/never-forget/server/node_modules/express/lib/response.js:170:12) at /home/kyle/programming/projects/never-forget/server/src/controllers/users.js:47:22 at at process._tickDomainCallback (internal/process/next_tick.js:229:

cannot set headers after they are sent is self-explanatory, but I do not see where in my program I have attempted to send headers after the request is sent. Seeing as res.send ends the request, I don't see what else should be included.

Upvotes: 1

Views: 67

Answers (2)

user11640989
user11640989

Reputation:

Try this one

User.exists({ email })
.then(userExists => {
    if (userExists.length >= 1) {
        return res.status(409).json({
            message: "Mail exists"
        });
    } else {
        newUser.save()
            .then(result => console.log('new user successfully registered!:', result))
            .catch(err => {
                console.error('Cannot save user: ', err)
            });
    }
});

Upvotes: 0

shubhambharti201
shubhambharti201

Reputation: 380

The problem i can think of is :

In callback implementation, when userExists is true, you are calling return res.status(400).send("A user with that email already exists") which ends the callback and res.status(201).send({...}) doesn't get called.

But, In promise implementation, when userExists is true, both of them will be called.

So, you can throw an error after return res.status(400).send("A user with that email already exists"), and catch that in catch block where it will end the main callback i.e. by return next(err);

Upvotes: 0

Related Questions