From 6b0f29a065466b7e3a78dad616a0775cc09fd2b3 Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Wed, 5 Oct 2022 13:54:07 +0100 Subject: [PATCH] Document i8n for RFC 7807 problem details Expand the documentation for error responses and add details on using a MessageSource to customize and internationalize error details. See gh-28814 --- src/docs/asciidoc/web/webflux.adoc | 129 ++++++++++++++++++++++---- src/docs/asciidoc/web/webmvc.adoc | 144 ++++++++++++++++++++++++++--- 2 files changed, 241 insertions(+), 32 deletions(-) diff --git a/src/docs/asciidoc/web/webflux.adoc b/src/docs/asciidoc/web/webflux.adoc index c4d89e776f..902f8e6fc9 100644 --- a/src/docs/asciidoc/web/webflux.adoc +++ b/src/docs/asciidoc/web/webflux.adoc @@ -3492,28 +3492,35 @@ include::webflux-cors.adoc[leveloffset=+1] [[webflux-ann-rest-exceptions]] -== REST API exceptions -[.small]#<># +== Error Responses +[.small]#<># -A common requirement for REST services is to include details in the body of an error -response. The Spring Framework supports the "Problem Details for HTTP APIs" -specification, https://www.rfc-editor.org/rfc/rfc7807.html[RFC 7807]. These are the main -abstractions for this support: +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 +encapsulate and expose the details of how they map to an HTTP response. All Spring WebFlux exceptions implement this. - `ErrorResponseException` -- basic `ErrorResponse` implementation that others can use as a convenient base class. - `ResponseEntityExceptionHandler` -- convenient base class for an -<> that handles all Spring MVC exceptions, +<> that handles all Spring WebFlux exceptions, and any `ErrorResponseException`, and renders an error response with a body. -You can return `ProblemDetail` or `ErrorResponse` directly from `@RequestMapping` or -from `@ExceptionHandler` controller methods to render an RFC 7807 response as follows: + + +[[webflux-ann-rest-exceptions-render]] +=== Render +[.small]#<># + +You can return `ProblemDetail` or `ErrorResponse` from any `@ExceptionHandler` or from +any `@RequestMapping` method to render an RFC 7807 response 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 @@ -3522,20 +3529,106 @@ already set. "application/problem+json" over "application/json" when rendering a `ProblemDetail`, and also falls back on it if no compatible media type is found. -You can extend an RFC 7807 response with non-standard fields as follows: +To enable RFC 7807 responses for Spring WebFlux exceptions and for any +`ErrorResponseException`, extend `ResponseEntityExceptionHandler` and declare it as an +<> in Spring configuration. The handler +obtains HTTP status, headers, and error details from each exception and prepares a +`ResponseEntity`. + + + +[[webflux-ann-rest-exceptions-non-standard]] +=== Non-Standard Fields +[.small]#<># + +You can extend an RFC 7807 response with non-standard fields in one of two ways. -- Insert into the "properties" `Map` of `ProblemDetail`. When using the Jackson +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`. -- Extend `ProblemDetail` to add dedicated non-standard properties. The copy constructor -in `ProblemDetail` allows a sub-class 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. -A client application can catch `WebClientResponseException` and use its +You can also extend `ProblemDetail` to add dedicated non-standard properties. +The copy constructor in `ProblemDetail` allows a sub-class 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. + + + +[[webflux-ann-rest-exceptions-i8n]] +=== Internationalization +[.small]#<># + +It is a common requirement to internationalize error response details, and good practice +to customize the problem details for Spring WebFlux exceptions. This is supported as follows: + +- Each `ErrorResponse` exposes a message code and message code arguments to resolve the +problem "detail" field through a <>. +The actual message code value is parameterized with placeholders, e.g. +`"HTTP method {0} not supported"` to be expanded from the arguments. +- `ResponseEntityExceptionHandler` uses the message code and the message arguments +to resolve the problem "detail" field. + +Message codes default to "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 +WebFlux exceptions: + +[[webflux-ann-rest-exceptions-codes]] +[cols="1,1,2", options="header"] +|=== +| Exception | Message Code | Message Code Arguments + +| `UnsupportedMediaTypeStatusException` +| (default) +| `{0}` the media type that is not supported, `{1}` list of supported media types + +| `UnsupportedMediaTypeStatusException` +| (default) + ".parseError" +| + +| `MissingRequestValueException` +| (default) +| `{0}` a label for the value (e.g. "request header", "cookie value", ...), `{1}` the value name + +| `UnsatisfiedRequestParameterException` +| (default) +| `{0}` the list of parameter conditions + +| `WebExchangeBindException` +| (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`. + +| `NotAcceptableStatusException` +| (default) +| `{0}` list of supported media types + +| `NotAcceptableStatusException` +| (default) + ".parseError" +| + +| `ServerErrorException` +| (default) +| `{0}` the failure reason provided to the class constructor + +| `MethodNotAllowedException` +| (default) +| `{0}` the current HTTP method, `{1}` the list of supported HTTP methods + +|=== + + + +[[webflux-ann-rest-exceptions-client]] +=== Client Handling +[.small]#<># + +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`. diff --git a/src/docs/asciidoc/web/webmvc.adoc b/src/docs/asciidoc/web/webmvc.adoc index eec33cc4b1..c5e2cca7f0 100644 --- a/src/docs/asciidoc/web/webmvc.adoc +++ b/src/docs/asciidoc/web/webmvc.adoc @@ -4824,13 +4824,14 @@ include::webmvc-cors.adoc[leveloffset=+1] [[mvc-ann-rest-exceptions]] -== REST API exceptions +== Error Responses [.small]#<># -A common requirement for REST services is to include details in the body of an error -response. The Spring Framework supports the "Problem Details for HTTP APIs" -specification, https://www.rfc-editor.org/rfc/rfc7807.html[RFC 7807]. These are the main -abstractions for this support: +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. @@ -4844,8 +4845,14 @@ can use as a convenient base class. <> that handles all Spring MVC exceptions, and any `ErrorResponseException`, and renders an error response with a body. -You can return `ProblemDetail` or `ErrorResponse` directly from `@RequestMapping` or -from `@ExceptionHandler` controller methods to render an RFC 7807 response as follows: + + +[[mvc-ann-rest-exceptions-render]] +=== Render +[.small]#<># + +You can return `ProblemDetail` or `ErrorResponse` from any `@ExceptionHandler` or from +any `@RequestMapping` method to render an RFC 7807 response 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 @@ -4854,18 +4861,127 @@ already set. "application/problem+json" over "application/json" when rendering a `ProblemDetail`, and also falls back on it if no compatible media type is found. -You can extend an RFC 7807 response with non-standard fields as follows: +To enable RFC 7807 responses for Spring MVC exceptions and for any +`ErrorResponseException`, extend `ResponseEntityExceptionHandler` and declare it as an +<> in Spring configuration. The handler +obtains HTTP status, headers, and error details from each exception and prepares a +`ResponseEntity`. + -- Insert into the "properties" `Map` of `ProblemDetail`. When using the Jackson + +[[mvc-ann-rest-exceptions-non-standard]] +=== Non-Standard Fields +[.small]#<># + +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`. -- Extend `ProblemDetail` to add dedicated non-standard properties. The copy constructor -in `ProblemDetail` allows a sub-class 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. + +You can also extend `ProblemDetail` to add dedicated non-standard properties. +The copy constructor in `ProblemDetail` allows a sub-class 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-i8n]] +=== Internationalization +[.small]#<># + +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 message code arguments to resolve the +problem "detail" field through a <>. +The actual message code value is parameterized with placeholders, e.g. +`"HTTP method {0} not supported"` to be expanded from the arguments. +- `ResponseEntityExceptionHandler` uses the message code and the message arguments +to resolve the problem "detail" field. + +Message codes default to "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) +| + +| `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" +| + +| `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) +| + +| `UnsatisfiedServletRequestParameterException` +| (default) +| `{0}` the list of parameter conditions + +|=== + + + +[[mvc-ann-rest-exceptions-client]] +=== Client Handling +[.small]#<># A client application can catch `WebClientResponseException`, when using the `WebClient`, or `RestClientResponseException` when using the `RestTemplate`, and use their