1

I have the following function for handling a user registration in node.js v8.9:

module.exports = async (req,res) =>{
    const User = req.app.locals.User;
    const user =User.build({
        email: req.body.email,
        displayName: req.body.display_name,
        realName: req.body.real_name,
        hashedPassword:req.body.password ,
        role: 0   
    });

    try{
        await user.save();
        res.send({message:"Usuario creado exitosamente.", success:true });
    }
    catch(ex)
    {
        res.send({message:"Información es inválida:", success:false});
    }

    res.end();
};

As you can see I am using async and await for handling when the user does not create successfully. However, my catch() never executes when creation fails. Why? Is there a different way to handle promise rejections with async/await? Someone suggested using thow new Error(), but I don't want to throw an error, I just want to send a message back to the client.

More background info: the app is made with Express.js, and using Sequelize.js as an ORM. I have saved my User model into req.app.locals to that I have access to it from my route handlers. The datatable, actually saving into MS SQL Server, has a UNIQUE constraint on the email column, to a User registering with an already existing e-mail would cause the user.save() promise to fail.

When testing, in the console, I see the exception from sequelize.js saying that the UNIQUE constraint did not allow the record creation. However, my catch statement does not get executed and the client (in this case the browser), remains waiting for a response until it times out. If I change the async/await to use .then() and .catch() it works correctly (no try/catch block needed, either).

halfer
  • 19,824
  • 17
  • 99
  • 186
tutiplain
  • 1,427
  • 4
  • 19
  • 37
  • possible that your User.save() isnt properly rejecting the promise. – j_mcnally Dec 30 '17 at 20:15
  • What do you mean by "creation fails"? Does `User.build` throw an exception or what? – Bergi Dec 30 '17 at 20:20
  • 2
    I'm voting to close as a problem missing a [mcve], but your title question would be a duplicate of [Correct Try…Catch Syntax Using Async/Await](https://stackoverflow.com/q/44663864/1048572) – Bergi Dec 30 '17 at 20:28
  • Does `user.save()` return a promise that sometimes rejects? – jfriend00 Dec 30 '17 at 21:05
  • the User.build() comes from sequelize.js, an ORM for node. In the documentation it says that it returns a promise. Creation can fail if, say, a User with the same e-mail address exists, as there is a UNIQUE constraint in the table. – tutiplain Dec 30 '17 at 22:14
  • 1
    @tutiplain Sounds like you will want to `await` the `build` call then, and put it inside the `try` block not before it. – Bergi Dec 30 '17 at 23:59
  • 1
    @Bergi - Per [this doc](http://docs.sequelizejs.com/class/lib/model.js~Model.html#static-method-build) it looks like `User.build()` returns a model and is not async. And, [`user.save()`](http://docs.sequelizejs.com/class/lib/model.js~Model.html#instance-method-save) appears to be async and does return a promise. Not sure where the error is unless `User` is not what the OP thinks it is and an exception is thrown before the `try` block. – jfriend00 Dec 31 '17 at 01:00
  • Probably not related to the problem you're writing about, but if this is Express, then your `res.send()` should be `res.json()` and remove the `res.end()`. – jfriend00 Dec 31 '17 at 01:02
  • @jfriend00 After using res.json() as you suggested and removing res.end(), it works as expected! – tutiplain Dec 31 '17 at 13:02

3 Answers3

0

try / catch. as the promise rejection in an await will throw an exception.

j_mcnally
  • 6,928
  • 2
  • 31
  • 46
0

I see a couple of issues (which apparently turn out to be causing your problem):

  1. Change both instances of res.send() to res.json().
  2. Remove the res.end().

If you want to send an object as the response, then you need to send JSON. You can either do res.send(JSON.stringify(obj)) or Express has res.json(obj) to convert the object for you.

And, res.end() is only needed with res.write(). Both res.send() and res.json() already include res.end().

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • This works, but I don't understand why. What difference does it make that I use res.end()? – tutiplain Dec 31 '17 at 17:56
  • @tutiplain - Your question was never very specific about what error was occurring and where in your code that was happening. If you want to debug your old code, then you should just instrument it with `console.log()` statements to follow the code flow and see exactly what was happening. We can't do that for you. Calling `res.end()` after `res.send()` or `res.json()` is an error because both `res.send()` and `res.json()` already call `res.end()` internally. I don't know exactly what happens when you call `res.end()` twice on the same response, but it is incorrect. – jfriend00 Dec 31 '17 at 18:03
  • @tutiplain - `res.json()` is required to get a proper JSON response sent. Trying to do `res.send(obj)` will end up sending a string `[object Object]` which is probably not what your recipient is expecting. – jfriend00 Dec 31 '17 at 18:07
-3

A correct way is to affect the returned value to variable like that:

try{
        [err,resp] = await user.save();
        res.send({message:"Usuario creado exitosamente.", success:true });
}

You can then check if you have error for eg

nodeover
  • 301
  • 1
  • 2
  • 11