HTTP APIのエラー処理の難しさとRFC7807
(gosuda.org)HTTP APIを開発する際、エラー処理はしばしば煩雑な部分になります。APIの数が増え、内部ロジックが複雑になるほど、3つの側面で難しさが生じます。
- 適切なエラーコードの返却: 経験の浅い開発者の場合、複雑なロジックの中で一貫したHTTPステータスコードを使うのは簡単ではありません。
- 大量の結果ログ作成: エラー発生時に想定されるすべての終了地点へログを記録することは、コード量を増やし、管理を複雑にします。
- 明確なエラーメッセージの送信: クライアントへ単にエラーメッセージを渡すだけでは、エラーを明確に理解して処理するのが困難です。
適切なエラーコード返却の改善
エラーコード利用の一貫性の問題を解決するために、StatusCodeとMessageを含むHttpErrorインターフェースまたは構造体を実装する方法を提案します。
- 解決策:
HttpError型を定義: HTTPステータスコードとメッセージをカプセル化。- ヘルパー関数を提供:
httperror.BadRequest("wrong format")のように、特定のエラーコードを返すヘルパー関数を使ってエラーオブジェクトを簡単に生成。
- 利点:
- IDEの自動補完機能を活用し、便利かつ安全にエラーコードとメッセージを入力可能。
- 数値コードを手入力するよりも、ミスの発生可能性を低減。
- あらかじめ用意された設計ドキュメントをいちいち確認する手間を削減。
ログ作成の集約
繰り返しのログ作成を減らし、エラー処理ロジックを1か所で管理するために、HTTPハンドラーをラップする方法を示します。
- 解決策:
- カスタムルーター(
chiwrap.Router)の実装:chi.Routerのような既存ルーターを内部に含み、エラー処理ロジックを追加します。 - ハンドラーのラップ: カスタムルーターの
GetなどのメソッドはHandlerFuncを受け取り、内部で実行し、エラーが発生した場合は集約処理ロジックへ渡します。 - エラーコールバック関数:
NewRouter作成時にerrCallback関数を受け取り、エラー発生時にそのコールバックを呼び出して、中央でログを記録したり追加処理を行ったりします。
- カスタムルーター(
- 利点:
- APIロジックでエラーが発生すると、自動的に適切なエラーコードとメッセージがレスポンスとして返される。
- サービスごとに適切なログを記録するようコールバック関数を登録でき、ログ管理が容易。
- コードの重複を減らし、保守性を向上。
明確なエラーメッセージの送信(RFC7807の活用)
クライアントがエラーをより明確に理解して処理できるよう、RFC7807標準を活用した構造化エラーメッセージの送信方法を提案します。
- RFC7807の主要要素:
type: エラー種別を識別するURI(例:https://example.com/errors/validation)。title: エラーに関する短い1行説明。status: HTTPステータスコードと同じ。detail: 人が読める詳細なエラー説明。instance: エラーが発生した特定のURI(例:/api/users/abc)。extensions: 追加情報を含むJSONオブジェクト(例:invalid_field,expected_format)。
- 実装:
-
RFC7807Error構造体を作成し、主要要素を含める。 -
メソッドチェーンパターン(
WithType(),WithInstance(),WithExtension())によって、構造化されたエラーオブジェクトを簡単に生成。 -
ToHttpError()メソッドを通じてRFC7807ErrorをHttpErrorに変換し、集約ルーターと連携可能。 -
クライアントがエラーの種類、原因、発生位置などを明確に把握可能。
-
APIレスポンスの一貫性と有用性を高め、クライアント開発の効率を向上。
-
5件のコメント
良い記事をありがとうございます
良い記事をありがとうございます!
参考までに、Spring では
spring-webライブラリのorg.springframework.http.ProblemDetailに実装が存在します!良い紹介をありがとうございます!
調べてみたところ、RFC 9457 に置き換えられていましたね。
https://datatracker.ietf.org/doc/html/rfc9457
(従来の 7807 文書: https://datatracker.ietf.org/doc/html/rfc7807)
RFC 7807 と RFC 9457 の主な違い
errors配列を使って関連エラーをグループ化pointerフィールドを正式サポート2023年7月以降の新規プロジェクトでは RFC 9457 の適用を推奨
typeフィールドは、参照解決可能な URI に設定することが推奨されているようです。内部サービスでは、Swagger-ui のドキュメントリンクで代用しても問題ないと思います。