You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
7.4 KiB
203 lines
7.4 KiB
[[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]] |
|
== Customization and i18n |
|
[.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 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 xref:core/beans/context-introduction.adoc#context-functionality-messagesource[MessageSource] |
|
and updates the corresponding `ProblemDetail` fields accordingly. |
|
|
|
The default strategy for message codes follows the pattern: |
|
|
|
`problemDetail.[type|title|detail].[fully qualified exception class name]` |
|
|
|
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: |
|
|
|
[[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 |
|
|
|
| `HandlerMethodValidationException` |
|
| (default) |
|
| `+{0}+` list all validation errors. |
|
Message codes and arguments for each error are also resolved via `MessageSource`. |
|
|
|
| `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 are also resolvedvia `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) |
|
| |
|
|
|
| `NoResourceFoundException` |
|
| (default) |
|
| |
|
|
|
| `TypeMismatchException` |
|
| (default) |
|
| `+{0}+` property name, `+{1}+` property value |
|
|
|
| `UnsatisfiedServletRequestParameterException` |
|
| (default) |
|
| `+{0}+` the list of parameter conditions |
|
|
|
|=== |
|
|
|
NOTE: 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 |
|
xref:core/beans/context-introduction.adoc#context-functionality-messagesource[MessageSource] |
|
resource bundle. See |
|
xref:core/validation/beanvalidation.adoc#validation-beanvalidation-spring-method-i18n[Customizing Validation Errors] |
|
for more details. |
|
|
|
|
|
|
|
[[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`. |
|
|
|
|
|
|
|
|