Java – Handling validation/exception responses in rest-ful app

javaspringspring-mvcweb-applications

So I am facing a problem with handling all sorts of exceptions within spring-boot application. Basically project is structured:

back-end (services, repositories) <—– RestControllers <—- UI (React\Angular)

The gist is that UI depends on Rest API wile rest API depends on Back-end services

Now – Rest API is designed around its own RESOURCES and back-end services around their own DTO's.
Currently validation is done in two places: RestControllers and Services while UI just displays the responses (validation errors).

Problem:
The usual validation problem in RestController's is acquiring valid resource. And this is handled nicely with combination of @Valid, JSR 303 Bean Validation and @ControllerAdvice. And this translates to something like:
[field: ..., error: ...]…
But what about other problems ? DB Constraint exceptions e.g. ? So validation can also be done in service layer but then exceptions no longer are adhering same standard as [field: ..., error: ...]. Also exception thrown by service needs to be translated into specific response RESOURCE. Now there is more than one error resource and this would only keep on growing.

Given the similar situation, what are best practices in such situation ?

Best Answer

I'll give an example using Spring REST as it has really nice built-in fucntionality for handling this problem and is probably the most popular Java REST implementation out there at the moment. One strategy is to use the Spring @ControllerAdvice annotation. This allows you to annotate a class containing exception translation logic to handle whatever exceptions arise during the processing of a request.

Methods within the class can then be annotated with the @ExceptionHandler and @ResponseStatus annotations, to define the logic for various exceptions.

For example, if we want to handle an exception that's thrown when the REST call fails to locate a resource from the persistence layer as described in the question...

    @ExceptionHandler(EmptyResultDataAccessException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public SimpleErrorModel handleEmptyDataException(HttpServletRequest request, Exception exception) {
        LOGGER.debug(exception);
        return new SimpleErrorModel("Resource not found");
    }

Or if a DataIntegrityViolationException gets thrown...

    @ExceptionHandler(DataIntegrityViolationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public SimpleErrorModel handleDataIntegrityViolationException(HttpServletRequest request, Exception exception) {
        LOGGER.debug(exception);
        return new SimpleErrorModel("Data integrity violation");
    }

This way, when any exception gets thrown, Spring will locate the appropriate class marked with the @ControllerAdvice annotation and then search for the correct exception translation method. It resolves this method and executes the logic in the method. Here, I've got a SimpleErrorModel class that looks like this...

public class SimpleErrorModel {

    private String errorMessage;
    private String moreInfo;

    public SimpleErrorModel(String errorMessage) {
        this(errorMessage, "");
    }

    public SimpleErrorModel(String errorMessage, String moreInfo) {
        this.errorMessage = errorMessage;
        this.moreInfo = moreInfo;
    }
}

...that then gets serialized via Spring REST and returned to the front-end with the correct response code. You can also pass the HttpResponse object in to the method and do whatever you like with it.

This is just one strategy but it has the advantage of keeping all of your error handling logic and should be absolutely fine for 90% of use cases. If you need more fine-grained control, you can add qualifiers to the @ControllerAdvice annotation...

    @ControllerAdvice(annotations = RestController.class)

...to restrict the annotated classes that this handler is used for.