spring-framework/framework-docs/modules/ROOT/pages/web/webmvc/mvc-ann-rest-exceptions.adoc

190 lines
7.0 KiB
Plaintext

[[mvc-ann-rest-exceptions]]
= Error Responses
[.small]#xref:web/webflux/ann-rest-exceptions.adoc[See equivalent in the Reactive stack]#
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, https://www.rfc-editor.org/rfc/rfc7807.html[RFC 7807].
The following are the main abstractions for this support:
- `ProblemDetail` -- representation for an RFC 7807 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 7807; this allows exceptions to
encapsulate and expose the details of how they map to an HTTP response. All Spring MVC
exceptions implement this.
- `ErrorResponseException` -- basic `ErrorResponse` implementation that others
can use as a convenient base class.
- `ResponseEntityExceptionHandler` -- convenient base class for an
xref:web/webmvc/mvc-controller/ann-advice.adoc[@ControllerAdvice] that handles all Spring MVC exceptions,
and any `ErrorResponseException`, and renders an error response with a body.
[[mvc-ann-rest-exceptions-render]]
== Render
[.small]#xref:web/webflux/ann-rest-exceptions.adoc#webflux-ann-rest-exceptions-render[See equivalent in the Reactive stack]#
You can return `ProblemDetail` or `ErrorResponse` from any `@ExceptionHandler` or from
any `@RequestMapping` method to render an RFC 7807 response. This is processed as follows:
- The `status` property of `ProblemDetail` determines the HTTP status.
- The `instance` property of `ProblemDetail` 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 a `ProblemDetail`,
and also falls back on it if no compatible media type is found.
To enable RFC 7807 responses for Spring WebFlux exceptions and for any
`ErrorResponseException`, extend `ResponseEntityExceptionHandler` and declare it as an
xref:web/webmvc/mvc-controller/ann-advice.adoc[@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`.
[[mvc-ann-rest-exceptions-non-standard]]
== Non-Standard Fields
[.small]#xref:web/webflux/ann-rest-exceptions.adoc#webflux-ann-rest-exceptions-non-standard[See equivalent in the Reactive stack]#
You can extend an RFC 7807 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.
[[mvc-ann-rest-exceptions-i18n]]
== Internationalization
[.small]#xref:web/webflux/ann-rest-exceptions.adoc#webflux-ann-rest-exceptions-i18n[See equivalent in the Reactive stack]#
It is a common requirement to internationalize error response details, and good practice
to customize the problem details for Spring MVC exceptions. This is supported as follows:
- Each `ErrorResponse` exposes a message code and arguments to resolve the "detail" field
through a xref:core/beans/context-introduction.adoc#context-functionality-messagesource[MessageSource].
The actual message code value is parameterized with placeholders, e.g.
`+"HTTP method {0} not supported"+` to be expanded from the arguments.
- Each `ErrorResponse` also exposes a message code to resolve the "title" field.
- `ResponseEntityExceptionHandler` uses the message code and arguments to resolve the
"detail" and the "title" fields.
By default, the message code for the "detail" field is "problemDetail." + the fully
qualified exception class name. Some exceptions may expose additional message codes in
which case a suffix is added to the default message code. The table below lists message
arguments and codes for Spring MVC exceptions:
[[mvc-ann-rest-exceptions-codes]]
[cols="1,1,2", options="header"]
|===
| Exception | Message Code | Message Code Arguments
| `AsyncRequestTimeoutException`
| (default)
|
| `ConversionNotSupportedException`
| (default)
| `+{0}+` property name, `+{1}+` property value
| `HttpMediaTypeNotAcceptableException`
| (default)
| `+{0}+` list of supported media types
| `HttpMediaTypeNotAcceptableException`
| (default) + ".parseError"
|
| `HttpMediaTypeNotSupportedException`
| (default)
| `+{0}+` the media type that is not supported, `+{1}+` list of supported media types
| `HttpMediaTypeNotSupportedException`
| (default) + ".parseError"
|
| `HttpMessageNotReadableException`
| (default)
|
| `HttpMessageNotWritableException`
| (default)
|
| `HttpRequestMethodNotSupportedException`
| (default)
| `+{0}+` the current HTTP method, `+{1}+` the list of supported HTTP methods
| `MethodArgumentNotValidException`
| (default)
| `+{0}+` the list of global errors, `+{1}+` the list of field errors.
Message codes and arguments for each error within the `BindingResult` are also resolved
via `MessageSource`.
| `MissingRequestHeaderException`
| (default)
| `+{0}+` the header name
| `MissingServletRequestParameterException`
| (default)
| `+{0}+` the request parameter name
| `MissingMatrixVariableException`
| (default)
| `+{0}+` the matrix variable name
| `MissingPathVariableException`
| (default)
| `+{0}+` the path variable name
| `MissingRequestCookieException`
| (default)
| `+{0}+` the cookie name
| `MissingServletRequestPartException`
| (default)
| `+{0}+` the part name
| `NoHandlerFoundException`
| (default)
|
| `TypeMismatchException`
| (default)
| `+{0}+` property name, `+{1}+` property value
| `UnsatisfiedServletRequestParameterException`
| (default)
| `+{0}+` the list of parameter conditions
|===
By default, the message code for the "title" field is "problemDetail.title." + the fully
qualified exception class name.
[[mvc-ann-rest-exceptions-client]]
== Client Handling
[.small]#xref:web/webflux/ann-rest-exceptions.adoc#webflux-ann-rest-exceptions-client[See equivalent in the Reactive stack]#
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`.