Handling Exceptions

AdonisJs not only treats exceptions as a way to guide the developer on what went wrong but also as a way to build application flow around them.

In this guide, we learn how exceptions are raised, how to write logic around them and finally creating your custom exceptions.

Introduction

Exceptions are great since they halt the program at a certain stage and makes sure that everything is correct before proceeding.

Usually, exceptions are just considered as a bunch of text, to tell the developer about what went wrong. If handled carefully they can help you build application flow around it.

By default, AdonisJs handles all the exceptions for you and display them in a nice format during development. However, you are free to handle exceptions of your own.

Handling exceptions

Exceptions can be handled by binding a wildcard exception handler or handling individual exceptions using their names.

Let’s start with the wildcard handler by creating an exception handler using the adonis command line tool.

Wildcard handler

adonis make:ehandler

Output

✔ create  app/Exceptions/Handler.js

Once you create this file, AdonisJs hands over all the exceptions occurred during HTTP lifecycle to it. It should have the handle method with an optional report method on it.

class ExceptionHandler {

  async handle (error, { response, session }) {
    if (error.name === 'ValidationException') {
      session.withErrors(error.messages).flashAll()
      await session.commit()
      response.redirect('back')
      return
    }

    response.status(error.status).send(error.message)
  }
}

module.exports = ExceptionHandler

The handle method in this class handles the ValidationException differently by flashing the errors back to the form.

Also, the report method may be used to report the exception to a 3rd party service like Bugsnag for logging purposes.

Individual exceptions

Also, you can hook into individual exceptions by defining an inline exception handler for them. The same can be done inside the start/hooks.js file.

const { hooks } = require('@adonisjs/ignitor')

hooks.after.providersBooted(() => {
  const Exception = use('Exception')

  Exception.handle('ValidationException', async (error, { response, session }) => {
    session.withErrors(error.messages).flashAll()
    await session.commit()
    response.redirect('back')
    return
  })
})

Custom exceptions

We learned how to handle certain exceptions with their names. Also, Adonisjs makes it so simple to build your custom exceptions and define handlers for them.

All the exceptions are stored inside app/Exceptions folder and as always let’s use the adonis command to create an exception.

adonis make:exception Custom

Output

✔ create  app/Exceptions/CustomException.js
const GE = require('@adonisjs/generic-exceptions')

class CustomException extends GE.LogicalException {
}

module.exports = CustomException

Now you can throw this exception just by importing the exceptions file. The status and code are optional when throwing the exception.

const CustomException = use('App/Exceptions/CustomException')

throw new CustomException(message, status, code)

The beauty of this approach is that you can give a unique name to your exceptions as the class name and then catch them accordingly.

A step further

Also, we can take a step further and define the handle and report methods on the exception itself. AdonisJs makes sure to call them if they exist.

class CustomException extends GE.LogicalException {
  handle (error, { response }) {
    response.status(500).send('Some message')
  }
}

module.exports = CustomException

Throwing the above exception calls the handle method on the exception itself to handle it.