Error Handling

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 own custom exceptions.

Introduction

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

Exceptions are usually just treated as guides to tell the developer what went wrong, but if handled carefully, they can help you build application flow around them.

By default, AdonisJs handles all exceptions for you and displays them in a nice format during development. However, you are free to handle exceptions however you want.

Handling exceptions

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

Wildcard handler

Let’s create a wildcard exception handler using the adonis command:

> adonis make:ehandler
make:ehandler output
✔ create  app/Exceptions/Handler.js

Once created, the wildcard exception handler is passed all exceptions that occurred during the HTTP lifecycle:

app/Exceptions/Handler.js
const BaseExceptionHandler = use('BaseExceptionHandler')

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

    return super.handle(...arguments)
  }
}

module.exports = ExceptionHandler

In the example above, the handle method handles the ValidationException by flashing validation errors back to the form.

Individual exceptions

You can hook into individual exceptions by defining an inline handler for them.

This can be done inside the start/hooks.js file:

start/hooks.js
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

AdonisJs makes it simple to build your own custom exceptions and define handlers for them.

Let’s use the adonis command to create a custom exception:

> adonis make:exception Custom
make:exception output
✔ create  app/Exceptions/CustomException.js
app/Exceptions/CustomException.js
const { LogicalException } = require('@adonisjs/generic-exceptions')

class CustomException extends LogicalException {}

module.exports = CustomException

You can throw this exception by importing its source file (the status and code values are optional):

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 and respond to them appropriately.

A step further

We can take custom exception handling a step further by defining handle and report methods on our custom exception class:

app/Exceptions/CustomException.js
const { LogicalException } = require('@adonisjs/generic-exceptions')

class CustomException extends LogicalException {
  handle (error, { response }) {
    response
      .status(500)
      .send('Custom exception handled!')
  }
}

module.exports = CustomException

If set, AdonisJs calls the custom exception’s handle method to create and return the exception response.