エラーレスポンス

REST サービスの一般的な要件は、エラーレスポンスの本文に詳細を含めることです。Spring Framework は、「HTTP API の問題の詳細」仕様 RFC 9457 [IETF] (英語) をサポートします。

このサポートの主な抽象化は次のとおりです。

  • ProblemDetail — RFC 9457 の問題の詳細の表現。仕様で定義されている標準フィールドと非標準フィールドの両方を格納するシンプルなコンテナーです。

  • ErrorResponse — HTTP ステータス、レスポンスヘッダー、RFC 9457 形式の本文を含む HTTP エラーレスポンスの詳細を公開する契約。これにより、例外が HTTP レスポンスにどのようにマップされるかの詳細をカプセル化して公開できるようになります。すべての Spring WebFlux 例外はこれを実装しています。

  • ErrorResponseException — 他の人が便利な基本クラスとして使用できる基本的な ErrorResponse 実装。

  • ResponseEntityExceptionHandler — すべての Spring WebFlux 例外と任意の ErrorResponseException を処理し、本文でエラーレスポンスをレンダリングする @ControllerAdvice の便利な基本クラス。

レンダリング

任意の @ExceptionHandler または任意の @RequestMapping メソッドから ProblemDetail または ErrorResponse を返して、RFC 9457 レスポンスをレンダリングできます。これは次のように処理されます。

  • ProblemDetail の status プロパティは、HTTP ステータスを決定します。

  • ProblemDetail の instance プロパティは、まだ設定されていない場合、現在の URL パスから設定されます。

  • コンテンツネゴシエーションの場合、Jackson HttpMessageConverter は ProblemDetail をレンダリングするときに "application/json" よりも "application/problem+json" を優先し、互換性のあるメディア型が見つからない場合はそれにフォールバックします。

Spring、WebFlux 例外および任意の ErrorResponseException に対して RFC 9457 レスポンスを有効にするには、ResponseEntityExceptionHandler を継承し、Spring 構成で @ControllerAdvice として宣言します。ハンドラーには、すべての組み込み Web 例外を含むすべての ErrorResponse 例外を処理する @ExceptionHandler メソッドがあります。さらに例外処理メソッドを追加し、protected メソッドを使用して任意の例外を ProblemDetail にマップできます。

非標準フィールド

RFC 9457 レスポンスを非標準フィールドで拡張するには、次の 2 つの方法があります。

1 つは、ProblemDetail の「プロパティ」 Map に挿入します。Jackson ライブラリを使用する場合、Spring Framework は ProblemDetailJacksonMixin を登録します。これにより、この「プロパティ」 Map がラップ解除され、レスポンスで最上位の JSON プロパティとしてレンダリングされます。同様に、逆直列化中に不明なプロパティがこの Map に挿入されます。

また、ProblemDetail を継承して、専用の非標準プロパティを追加することもできます。ProblemDetail のコピーコンストラクターを使うと、既存の ProblemDetail からサブクラスを簡単に作成することができます。これは、たとえば、例外の ProblemDetail を再作成する ResponseEntityExceptionHandler などの @ControllerAdvice から、非標準のフィールドを追加したサブクラスを一元的に作成することが可能です。

カスタマイズと i18n

エラーレスポンスの詳細をカスタマイズして国際化するのは一般的な要件です。実装の詳細が明らかにならないように、Spring WebFlux 例外の問題の詳細をカスタマイズすることも推奨されます。このセクションではそのサポートについて説明します。

ErrorResponse は、"type"、"title"、"detail" のメッセージコードと、"detail" フィールドのメッセージコード引数を公開します。ResponseEntityExceptionHandler は MessageSource を通じてこれらを解決し、それに応じて対応する ProblemDetail フィールドを更新します。

メッセージコードのデフォルトの戦略は次のパターンに従います。

problemDetail.[type|title|detail].[fully qualified exception class name]

ErrorResponse は複数のメッセージコードを公開する場合があり、通常はデフォルトのメッセージコードにサフィックスを追加します。次の表に、Spring WebFlux 例外のメッセージコードと引数を示します。

例外 メッセージコード メッセージコードの引数

HandlerMethodValidationException

(デフォルト)

{0} list all validation errors. Message codes and arguments for each error are also resolved via MessageSource.

MethodNotAllowedException

(デフォルト)

{0} the current HTTP method, {1} the list of supported HTTP methods

MissingRequestValueException

(デフォルト)

{0} a label for the value (e.g. "request header", "cookie value", …​), {1} the value name

NotAcceptableStatusException

(デフォルト)

{0} list of supported media types

NotAcceptableStatusException

(デフォルト) + ".parseError"

ServerErrorException

(デフォルト)

{0} the failure reason provided to the class constructor

UnsupportedMediaTypeStatusException

(デフォルト)

{0} the media type that is not supported, {1} list of supported media types

UnsupportedMediaTypeStatusException

(デフォルト) + ".parseError"

UnsatisfiedRequestParameterException

(デフォルト)

{0} the list of parameter conditions

WebExchangeBindException

(デフォルト)

{0} はグローバルエラーのリスト、{1} はフィールドエラーのリストです。各エラーのメッセージコードと引数も MessageSource を介して解決されます。

他の例外とは異なり、WebExchangeBindException および HandlerMethodValidationException のメッセージ引数は、MessageSource リソースバンドルを通じてカスタマイズすることもできる MessageSourceResolvable エラーのリストに基づいています。詳細については、検証エラーのカスタマイズを参照してください。

クライアントハンドリング

クライアントアプリケーションは、WebClient を使用する場合は WebClientResponseException をキャッチし、RestTemplate を使用する場合は RestClientResponseException をキャッチし、それらの getResponseBodyAs メソッドを使用して、エラーレスポンスの本文を ProblemDetail や ProblemDetail のサブクラスなどの任意のターゲット型にデコードします。