Setting up a REST service using Spring Boot is simple. However, setting up consistent error handling for that service can be a bit more daunting.
You'll typically want your service to use one particular error structure (JSON) for every error generated by the application. The question is: how
do you do that in the simplest possible way with all the options you have available?
-
Option 1 - Servlet API Error Handling - The Servlet API itself contains an error handling system configured via web.xml. You can use
the <error-page> element to specify the response handler (a JSP, Servlet, ...) for certain exceptions and HTTP status codes.
In practice this means that if a Servlet or JSP generates an exception or calls HttpServletResponse.sendError(), the corresponding
<error-page> page will be sent back to the client.
-
Option 2 - Spring MVC Error Handling - Spring MVC's DispatcherServlet comes with it's own error handling system, implemented using a
HandlerExceptionResolver. In modern Spring applications this is typically setup using
@ExceptionHandler
@ControllerAdvice. When a request handler throws and exception, an appropriate exception handler is selected and tasked with
resolving the error by generating an error response. Note that if an exception handler resolves the error, the exception never
propagates up to the Servlet engine, meaning the defined Servlet error pages are not considered.
-
Option 3 - Spring Boot Error Handling - Spring Boot comes with a default error handling setup built on top of the Servlet API and Spring MVC error handling systems.
The default setup (see ErrorMvcAutoConfiguration) does three things:
- It configures a Servlet <error-page> directed at /error for all exceptions and response codes.
-
It defines an ErrorController handling /error requests, forwarded to it because of the configured Servlet error page.
The default ErrorController implementation is the BasicErrorController, which will try to resolve an "error" view
used to render a model prepared by an ErrorAttributes implementation.
If the client is requesting text/html, the default whitelabel error page (see below) will be used, otherwise the model will be
rendered directly as response body (typically JSON).
-
The whitelabel error page serves as a simplistic HTML "error" view detailing the error that occurred by rendering the model
prepared by the ErrorAttributes implementation.
That's a lot to take in! Customizing the default error structure (see
DefaultErrorAttributes) involves several steps:
- Define a class for your own error structure, say ErrorInfo.
- Implement approprate @ExceptionHandlers returning ResponseEntity<ErrorInfo> objects, typically in a
ResponseEntityExceptionHandler subclass.
- Implement an ErrorAttributes bean to return a Map (ugh!) corresponding with your ErrorInfo structure.
- Replace the whitelabel error page with one that can handle your ErrorInfo structure.
Although steps 1 and 2 make sense, steps 3 and 4 feel clumsy and unelegant.
Luckily there is a simpler way to do this if you're implementing a pure REST service that's only concerned with returning JSON responses,
while still leveraging part of the default setup done by Spring Boot (
ErrorMvcAutoConfiguration, specifically the
/error
Servlet error page).
- Of course you still need to define your own ErrorInfo structure.
- And you'll also still need to implement appropriate @ExceptionHandlers returning ResponseEntity<ErrorInfo> objects.
- Now implement an ErrorController that handles /error requests, returning an appropriate ResponseEntity<ErrorInfo>.
- Finally, disable the whitelabel error page by setting the server.error.whitelabel.enabled property to false.
That feels quite a bit better: all code uses your own
ErrorInfo class to render an error and you don't need to spend time implementing
an HTML error view for an application that should never output HTML anyway.
No comments:
Post a Comment