Organising NodeJS' Error Handling Hell with IcedCoffeeScript

Let’s suppose you are building a NodeJS application. Lets focus on only one request (let it be our custom authentication despite of the fact that there are ready to use modules such as Passport). After you handled all edge cases your code may look like this:

app.post '/api/authentication/', (req, res)->
  User.findOne
    email: req.body.email
    , (error, user)->
      if error
        res.json 504,
          success: false
          error_message: 'Database error while searching for user'
      else
        if not user
          res.json 403,
            success: false
            error_message: 'User with given email was not found' + req.body.email
        else
          if user.authenticate req.body.password
            # Save into session
            req.session.userId = user.id
            res.json
              success: true
              user: user.getPublicData()
          else
            res.json 403,
              success: false
              error_message: 'Email or password are wrong. Please check them and try one more time'

It looks quite deep. We can make it less deep by joining all if/else statements into one big if/else-if/else block:

app.post '/api/authentication/', (req, res)->
  User.findOne
    email: req.body.email
    , (error, user)->
      if error
        res.json 504,
          success: false
          error_message: 'Database error while searching for user'
      else if not user
        res.json 403,
          success: false
          error_message: 'User with given email was not found' + req.body.email
      else if user.authenticate req.body.password
        # Save into session
        req.session.userId = user.id
        res.json
          success: true
          user: user.getPublicData()
      else
        res.json 403,
          success: false
          error_message: 'Email or password are wrong. Please check them and try one more time'

Now this is much better, but still there is room for improvement. Lets add following function:

errorHandler = {}
errorHandler.json = (res, code, message)->
  res.json code,
    success: false
    error_message: message

Now we can rewrite our previous code to:

app.post '/api/authentication/', (req, res)->
  User.findOne
    email: req.body.email
    , (error, user)->
      return errorHandler.json res, 504, 'Database error while searching for user' if error
      return errorHandler.json res, 403, 'User with given email was not found' if not user
      return errorHandler.json res, 403, 'Email or password is wrong' if not user.authenticate req.body.password

      # Save into session
      req.session.userId = user.id
      res.json
        success: true
        user: user.getPublicData()

This looks much better then what we have at the beginning. But can we do even better? Yes we can! Let’s use the power of ice (or simply IcedCoffeeScript). By awaiting the findOne user callback we can change our previous code into this piece of beauty:

app.post '/api/authentication/', (req, res)->
  await User.findOne {email: req.body.email} , defer(error, user)

  return errorHandler.json res, 504, 'Database error while searching for user' if error
  return errorHandler.json res, 403, 'User with given email was not found' if not user
  return errorHandler.json res, 403, 'Email or password is wrong' if not user.authenticate req.body.password

  # Save into session
  req.session.userId = user.id
  res.json
    success: true
    user: user.getPublicData()

This way we shortened our code more then 2 times, changed maximal level of code depth from 7 to 2 thus making the code much more beautiful, readable and maintainable.