Error Handling

Beadledom has implemented a standard behavior for handling errors in a RESTful service that follows the Google API structured error message format. This format allows exceptions to be mapped to responses in JSON format with only the information that is necessary or desired for a consuming application.

Two models exist for the purpose of allowing easily-constructed JSON responses:

  • JsonError - A class that can be used to build a JSON response.
  • ErrorDetail - A class that can be used to add additional error details to the JSON response.

These models are serializable objects that can be set as the response’s entity body.

Example Response:

{
  "errors": [
    {
      "domain": "global",
      "reason": "notFound",
      "message": "Not Found"
    }
  ],
  "code": 404,
  "message": "Not Found"
}

Example Response (without additional errors information):

{
  "code": 404,
  "message": "Not Found"
}

Behavior

Without the use of an ExceptionMapper, an unhandled exception thrown from a resource endpoint will return an HTTP response in plain text or HTML that may contain stack traces or other system-specific information that should not be displayed to the end-user.

Beadledom addresses this concern by implementing exception mappers. By default, Beadledom comes packaged with five exception mappers that handle this functionality behind the scenes:

Each of these ExceptionMapper classes has a distinct role in a RESTful service.

The WebApplicationExceptionMapper is intended to handle all exceptions thrown from a service that extend from the WebApplicationException hierarchy. This includes exceptions such as BadRequestException, NotFoundException, custom exceptions extending from WebApplicationException, etc. WebApplicationExceptionMapper treats the exception as-is but sanitizes the exception’s response, status, and message and formats it as JSON before sending back a response. The status will be propagated through to the response. The response message will be derived from the resulting status code or the status code’s family if the status is unrecognized.

The FailureExceptionMapper is meant to be used with projects using Resteasy and handles all exceptions thrown internally by Resteasy that extend from the Failure hierarchy. Resteasy has built-in internally-thrown exceptions that need to be handled and reformatted before sending back a response. If the exception’s response is not null, its status code will be used as the status of the response. If the exception’s response is null, then the error code on the Failure exception will be used as the status of the response if it is in the valid status code range (100-599). If neither of these are true, the status is mapped to an Internal Server Error (500 status code). The response message will be derived from the resulting status code or the status code’s family if the status is unrecognized.

ThrowableExceptionMapper is the exception mapper that will behave as a catch-all for all exceptions that go unhandled. An unhandled exception could match any of the following scenarios:

  • The exception was a checked exception that was not handled by try/catch blocks.
  • The exception was a checked exception that was missing an exception mapper or the exception mapper was implemented incorrectly.
  • The exception was an unchecked exception.

Any exception thrown in a resource matching one of the scenarios mentioned above will be treated as an Internal Server Error (500 status code).

Keep in mind that an unhandled exception will be caught by the exception mapper that is most specific to the exception. If there is not an exception mapper for the specific exception, the next closest exception mapper in the exception’s hierarchy will handle it. For example, if a NotFoundException (which extends from WebApplicationException) is thrown, the WebApplicationExceptionMapper will handle it, rather than the ThrowableExceptionMapper.

Implementation

Each of the exception mappers mentioned above are readily available for consumption. They are automatically added to a project that have installed either the BeadledomModule (WebApplicationExceptionMapper and ThrowableExceptionMapper only) or the ResteasyModule (WebApplicationExceptionMapper, FailureExceptionMapper, and ThrowableExceptionMapper).

NOTE: If your service is able to throw custom exceptions, it is suggested that a custom ExceptionMapper is added to your project as well. This will allow you to customize the response that is returned; otherwise, there is a chance that the custom exception may be handled by the ThrowableExceptionMapper and return a 500 response, which may be undesired. While creating custom exception mappers, stay consistent with the error handling format by using the JsonError and ErrorDetail models to create the response entity.