A common requirement for REST services is to include details in the body of error responses. The Spring Framework supports the "Problem Details for HTTP APIs" specification, RFC 9457.
The following are the main abstractions for this support:
-
ProblemDetail
— representation for an RFC 9457 problem detail; a simple container for both standard fields defined in the spec, and for non-standard ones. -
ErrorResponse
— contract to expose HTTP error response details including HTTP status, response headers, and a body in the format of RFC 9457; this allows exceptions to encapsulate and expose the details of how they map to an HTTP response. All Spring MVC exceptions implement this. -
ErrorResponseException
— basicErrorResponse
implementation that others can use as a convenient base class. -
ResponseEntityExceptionHandler
— convenient base class for an @ControllerAdvice that handles all Spring MVC exceptions, and anyErrorResponseException
, and renders an error response with a body.
Render
You can return ProblemDetail
or ErrorResponse
from any @ExceptionHandler
or from
any @RequestMapping
method to render an RFC 9457 response. This is processed as follows:
-
The
status
property ofProblemDetail
determines the HTTP status. -
The
instance
property ofProblemDetail
is set from the current URL path, if not already set. -
For content negotiation, the Jackson
HttpMessageConverter
prefers "application/problem+json" over "application/json" when rendering aProblemDetail
, and also falls back on it if no compatible media type is found.
To enable RFC 9457 responses for Spring WebFlux exceptions and for any
ErrorResponseException
, extend ResponseEntityExceptionHandler
and declare it as an
@ControllerAdvice in Spring configuration. The handler
has an @ExceptionHandler
method that handles any ErrorResponse
exception, which
includes all built-in web exceptions. You can add more exception handling methods, and
use a protected method to map any exception to a ProblemDetail
.
Non-Standard Fields
You can extend an RFC 9457 response with non-standard fields in one of two ways.
One, insert into the "properties" Map
of ProblemDetail
. When using the Jackson
library, the Spring Framework registers ProblemDetailJacksonMixin
that ensures this
"properties" Map
is unwrapped and rendered as top level JSON properties in the
response, and likewise any unknown property during deserialization is inserted into
this Map
.
You can also extend ProblemDetail
to add dedicated non-standard properties.
The copy constructor in ProblemDetail
allows a subclass to make it easy to be created
from an existing ProblemDetail
. This could be done centrally, e.g. from an
@ControllerAdvice
such as ResponseEntityExceptionHandler
that re-creates the
ProblemDetail
of an exception into a subclass with the additional non-standard fields.
Customization and i18n
It is a common requirement to customize and internationalize error response details. It is also good practice to customize the problem details for Spring MVC exceptions to avoid revealing implementation details. This section describes the support for that.
An ErrorResponse
exposes message codes for "type", "title", and "detail", as well as
message code arguments for the "detail" field. ResponseEntityExceptionHandler
resolves
these through a MessageSource
and updates the corresponding ProblemDetail
fields accordingly.
The default strategy for message codes is as follows:
-
"type":
problemDetail.type.[fully qualified exception class name]
-
"title":
problemDetail.title.[fully qualified exception class name]
-
"detail":
problemDetail.[fully qualified exception class name][suffix]
An ErrorResponse
may expose more than one message code, typically adding a suffix
to the default message code. The table below lists message codes, and arguments for
Spring MVC exceptions:
Exception | Message Code | Message Code Arguments |
---|---|---|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) + ".parseError" |
|
|
(default) |
|
|
(default) + ".parseError" |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
Unlike other exceptions, the message arguments for
MethodArgumentValidException and HandlerMethodValidationException are baed on a list of
MessageSourceResolvable errors that can also be customized through a
MessageSource
resource bundle. See
Customizing Validation Errors
for more details.
|
Exception | Message Code | Message Code Arguments |
---|---|---|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) + ".parseError" |
|
|
(default) |
|
|
(default) + ".parseError" |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
|
(default) |
|
Unlike other exceptions, the message arguments for
MethodArgumentValidException and HandlerMethodValidationException are baed on a list of
MessageSourceResolvable errors that can also be customized through a
MessageSource
resource bundle. See
Customizing Validation Errors
for more details.
|
Client Handling
A client application can catch WebClientResponseException
, when using the WebClient
,
or RestClientResponseException
when using the RestTemplate
, and use their
getResponseBodyAs
methods to decode the error response body to any target type such as
ProblemDetail
, or a subclass of ProblemDetail
.