Previous Topic

Next Topic

Book Contents

Book Index

Defining Error Responses Using the REST Auxiliaries

This guide proved examples for using the Auxiliaries for defining Error Responses.

Implementation Tips

The Error Responses defining can be improved via some implementation tips as follow:

Example: Error Handling Using the Error Description Utils

The following example demonstrates error handling using the ErrorDescriptionUtils:

@Path("/demo/bookstore/books")

public class BookStoreService {

  /**

   * Retrieves a {@link BookResource} representation of book with identifier {@code bookId}. The {@link BookResource}

   * representation shall include all of the mandatory and any of the optional fields annotated with {@code GET}.

   .....

   * Possible HTTP error codes:

   * <ul>

   * <ol>

   * {@link HttpConnection#HTTP_BAD_REQUEST} with application error codes

   * {@link GeneralErrorCodes#INVALID_REPRESENTATION_CONSTRAINTS_SYNTAX},

   * {@link BookStoreErrorCodes#ILLEGAL_BOOK_IDENTIFIER}

   * </ol>

   * <ol>

   * {@link HttpConnection#HTTP_NOT_FOUND} with application error codes {@link BookStoreErrorCodes#BOOK_NOT_FOUND}

   * </ol>

   * <ol>

   * {@link HttpConnection#HTTP_FORBIDDEN} with application error code

   * {@link GeneralErrorCodes#INSUFFICIENT_PERMISSIONS}

   * </ol>

   * </ul>

   .....

   */

  @GET

  @Path("{bookId}")

  public Response getBook(@PathParam("bookId") long bookId) {

    // get book, check if exists

    Book book = findBook(bookId);

    // initialize book resource fields, build response

    return Response.ok(BookResourceFactory.getBookResource(book, constraints)).build();

  }

  // validate the provided book identifier and return appropriate error if identifier is invalid

  private Book findBook(long bookId) {

    if (bookId < 0) {

      ErrorDescriptionUtils.throwWebApplicationException(HttpURLConnection.HTTP_BAD_REQUEST,

          BookStoreErrorCodes.ILLEGAL_BOOK_IDENTIFIER, "Book identifier is incorrect: " + bookId,

          "Book identifier must be greater than 0!", BookResourceFields.BOOK_ID);

      return null;

    }

    Book book = bookStore.get(bookId);

    if (book == null) {

      ErrorDescriptionUtils.throwWebApplicationException(HttpURLConnection.HTTP_NOT_FOUND,

          BookStoreErrorCodes.BOOK_NOT_FOUND, "Book with identifier: " + bookId + " does not exist!",

          "Book with such identifier was not found. Try another!", BookResourceFields.BOOK_ID);

      return null;

    }

    return book;

  }

  .....

}

A sample error response reporting a book not found error containing an ErrorDescription representation in JSON:

GET /demo/bookstore/books/6 HTTP/1.1

Content-Type: application/json

Accept: application/json

Authorization: Basic YWRtaW46YWRtaW4=

HTTP/1.1 404 Not Found

Content-Type: application/json

{

   "status": 404,

   "code": 40010,

   "description": "Book with identifier: 6 does not exist!",

   "hint": "Book with such identifier was not found. Try another!",

   "source": "id"

}

A sample error response reporting an invalid book identifier error containing an ErrorDescription representation in JSON:

GET /demo/bookstore/books/-1 HTTP/1.1

Content-Type: application/json

Accept: application/json

Authorization: Basic YWRtaW46YWRtaW4=

HTTP/1.1 400 Bad Request

Content-Type: application/json

{

  "status": 400,

  "code": 40020,

  "description": "Book identifier is incorrect: -1",

  "hint": "Book identifier must be greater than 0!",

  "source": "id"

}

Example: Error Handling Using the Error Description Utils for Composite Errors

The following example demonstrates error handling using the ErrorDescriptionUtils for generating composite errors:

@Path("/demo/bookstore/books")

public class BookStoreService {

  /**

   * Updates the book with identifier {@code bookId} based on the new data included in the {@link BookResource}

   * representation transferred by the client. The {@link BookResource} representation may include all of the mandatory

   * and any of the optional fields annotated with {@code PUT}.

   .....

   * <ul>

   * <ol>

   * {@link HttpURLConnection#HTTP_BAD_REQUEST} with application error codes

   * {@link BookStoreErrorCodes#ILLEGAL_BOOK_RESOURCE_REPRESENTATION},

   * {@link BookStoreErrorCodes#ILLEGAL_BOOK_IDENTIFIER}, {@link BookStoreErrorCodes#ILLEGAL_BOOK_TITLE},

   * {@link BookStoreErrorCodes#ILLEGAL_BOOK_AUTHOR}, {@link BookStoreErrorCodes#ILLEGAL_BOOK_COUNT} or

   * {@link GeneralErrorCodes#COMPOSITE_ERROR}

   * </ol>

   * <ol>

   * {@link HttpURLConnection#HTTP_NOT_FOUND} with application error codes {@link BookStoreErrorCodes#BOOK_NOT_FOUND}

   * </ol>

   * <ol>

   * {@link HttpURLConnection#HTTP_FORBIDDEN} with application error code

   * {@link GeneralErrorCodes#INSUFFICIENT_PERMISSIONS}

   * </ol>

   * </ul>

   .....

   */

  @PUT

  @Path("{bookId}")

  public Response updateBook(@PathParam("bookId") long bookId, BookResource book) {

    // get book, check if exists

    Book storedBook = findBook(bookId);

    // validate the book resource provided for update

    validateBookResource(book);

    // update the stored book based on the provided fields for update

    if (book.getAuthor() != null) {

      storedBook.setAuthor(book.getAuthor());

    }

    if (book.getTitle() != null) {

      storedBook.setTitle(book.getTitle());

    }

    if (book.getCount() != null) {

      storedBook.setCount(book.getCount());

    }

    // reuse the provided book resource instance, reinit the fields and build response

    return Response.ok(BookResourceFactory.reinitBookResource(storedBook, book, constraints)).build();

  }

  // validate the provided book resource and return appropriate errors

  private void validateBookResource(BookResource book) {

    if (book == null) {

      ErrorDescriptionUtils.throwWebApplicationException(HttpURLConnection.HTTP_BAD_REQUEST,

          BookStoreErrorCodes.ILLEGAL_BOOK_RESOURCE_REPRESENTATION, "Book resource representation is missing!",

          "Book resource representation must be provided!", null);

    } else {

      List<ErrorDescription> errors = new LinkedList<ErrorDescription>();

      

      // validate the book title

      String title = book.getTitle();

      if (title != null && title.trim().isEmpty()) {

        errors.add(ErrorDescriptionUtils.getErrorDescription(HttpURLConnection.HTTP_BAD_REQUEST,

            BookStoreErrorCodes.ILLEGAL_BOOK_TITLE, "Book title is missing or empty string!",

            "Book title must be valid string!", BookResourceFields.TITLE));

      }

      

      // validate the book author

      String author = book.getAuthor();

      if (author != null && author.trim().isEmpty()) {

        errors.add(ErrorDescriptionUtils.getErrorDescription(HttpURLConnection.HTTP_BAD_REQUEST,

            BookStoreErrorCodes.ILLEGAL_BOOK_AUTHOR, "Book author is missing or empty string!",

            "Book author must be valid string!", BookResourceFields.AUTHOR));

      }

      

      // validate the books count

      Integer count = book.getCount();

      if (count != null && count < 0) {

        errors.add(ErrorDescriptionUtils.getErrorDescription(HttpURLConnection.HTTP_BAD_REQUEST,

            BookStoreErrorCodes.ILLEGAL_BOOK_COUNT, "Book count is missing or negative!",

            "Book count must be valid non negative integer!", BookResourceFields.COUNT));

      }

      

      // flatten the collection and throw WebApplicationException

      throwWebApplicationException(errors);

    }

  }

  private void throwWebApplicationException(List<ErrorDescription> errors) {

    if (errors.size() > 0) {

      if (errors.size() == 1) {

        ErrorDescriptionUtils.throwWebApplicationException(errors.get(0));

      } else {

        ErrorDescriptionUtils.throwWebApplicationException(HttpURLConnection.HTTP_BAD_REQUEST,

            "Multiple validation errors occured while processing the book resource representation!",

            "Please see the nested error descriptions for more details.",

            null, errors);

      }

    }

  }

  .....

}

A sample error response reporting a composite validation error containing an ErrorDescription representation in JSON:

GET /demo/bookstore/books/6 HTTP/1.1

Content-Type: application/json

Accept: application/json

Authorization: Basic YWRtaW46YWRtaW4=

HTTP/1.1 404 Not Found

Content-Type: application/json

{

  "status": 400,

  "code": 50010,

  "description": "Multiple validation errors occured while processing the book resource representation!",

  "hint": "Please see the nested error descriptions for more details.",

  "errors": [

    {

      "status": 400,

      "code": 40031,

      "description": "Book title is missing or empty string!",

      "hint": "Book title must be valid string!",

      "source": "title"

    },

    {

      "status": 400,

      "code": 40032,

      "description": "Book author is missing or empty string!",

      "hint": "Book author must be valid string!",

      "source": "author"

    },

    {

      "status": 400,

      "code": 40033,

      "description": "Book count is missing or negative!",

      "hint": "Book count must be valid non negative integer!",

      "source": "count"

    }

  ]

}