0

I'm writing an express JS app using this style for routing:

router.post('/account/create', async function(req, res, next) {
    var account = await db.query(`query to see if account exists`).catch(next);
    if (account) {
        res.send('Email is unavailable.');
    } else {
        // Create account
    }
});

If the query returns successful but with no rows, the route executes perfectly. account is empty and so the if statement works and we create an account.

However if there was an issue with the db query, the catch statement is called and account is undefined, so the function continues to attempt to create a new account, even though next has been called which logs the error and sends a 500.

In an effort to continue with the ease of this async/await simple coding style, is there a way to easily stop function execution (or another solution) to prevent the subsequent code from executing without going back to callbacks?

4
  • Why don't you use a try-catch block?` Commented Nov 3, 2018 at 23:14
  • Just trying to keep this super minimal coding style. One solution I just thougt of is returning an Error from my next function, and just adding !(account instanceof Error) to whatever if is directly after the await call. Commented Nov 3, 2018 at 23:18
  • @tkausl even a try-catch would put me in the same boat. I need to catch for every await call, so wrapping an entire route with multiple await calls would not work, and if i wrap every await call in a try-catch, again, code continues to be executed if it follows after the catch block. So I'd have to next all these try-catches and it would be just as bad as callbacks or worse. Commented Nov 3, 2018 at 23:25
  • Depending upon how you create the account, this could be a race condition. If some other request creates the account between the time you check for it and you then create it, you could end up with duplicate accounts. The DB needs to prevent duplicates. Commented Nov 4, 2018 at 4:16

2 Answers 2

2

Something like below should do the job?

It utilises try / catch, coupled with async/await, this way there are no callbacks.

router.post('/account/create', async function(req, res, next) {

  var account; 
  try {
      account = await db.query(`query to see if account exists`);
  } catch (e) {
    return res.status(500).send("Error checking if account exists.");
  }

  // If the account exists, return early
  if (account) {
    return res.status(500).send("Account already exists.");
  }

  // Account doesn't exist, so let's create the account!

  try {
    // Here you could create your new user account, and save it in the database, the catch would catch any DB error.

   // await db.query......

  } catch (e) {

    // Something went wrong creating the account, oops! Return.
    return res.status(500).send("Error creating account");
  }

  // The account would have been created at this point.
  return res.status(200).send("Account created!");
});

Using promises, without async/await.

router.post('/account/create', async function(req, res, next) {

  db.query(`query to see if account exists`)
    .then((account) => {

      // If the account exists, return early
      if (account) {
        return res.status(500).send("Account already exists.");
      }

      // Now create account
      db.query(`query to create account`)
        .then((result) => {

          // Account created fine, return.
          return res.status(200).send("Account created!");
        })
        .catch((err) => {

          // Error creating account, return.
          return res.status(500).send("Error creating account");
        });

    })
    .catch((err) => {
      return res.status(500).send("Error checking if account exists.");
    })

});
Sign up to request clarification or add additional context in comments.

8 Comments

I believe this would function the same as my example. Suppose the db query fails, that error is caught, account is now undefined, execution continues to the next try where it attempts to create a new account. I'd also prefer to not use try-catch as it's ugly as heck lol.
Well in my example I am returning if any error occurs, thus execution of this function is halted, and inside the if statement, checking for the account existing, I return there. In short ,the code above stops executing as soon as an error is encountered, or a user is already found.
I.e., if the code executes res.status(500).send('...'). Then that route returns, no further code for it is executed.
Ah, didn't see that. That works. Still would love to be able to use catch but maybe that's not possible.
It seems you have made a simple mistake, you have ommited return in your example, i.e. when you go 'res.send('')', you don't return, thus below code continues to execute with your example.
|
-1

I've decided to use the solution here which is to wrap my route handlers in a function that catches errors for the entire route handler and calls next. Then if I need to handle an error specifically I can use try-catch. So 90% of cases use the default next error handler, the other 10 just use try-catch.

Keeps everything clean and super convenient, and you don't ever have to use .catch() on await calls.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.