代表的な面接トピック

バックエンド面接:RFC 9457を用いた統合HTTP APIエラーコントラクトの設計

バックエンド普通
Offer.cc 編集チーム公開日 更新日

質問

エラー形式に一貫性のないHTTP APIを複数のクライアントが呼び出しています。タイプ、ステータスコード、バリデーションフィールド、リトライヒント、ローカライゼーション、および機密情報を網羅した、統一されたRFC 9457エラーレスポンスを設計してください。

出題の趣旨と範囲

このバックエンドの設問は、APIコントラクトと障害境界をテストします。目的はすべての例外を1つのJSONオブジェクトにラップすることではなく、ログ、トレーシング、権限、ユーザー向け文言を個別のレイヤーとして維持しながら、クライアントが安定したアクションを実行できるようにすることです。

面接官が評価しているポイント

  • application/problem+jsonとHTTPステータスコードの関係を理解しているか。
  • バリデーション、認証、認可、競合、レート制限、一時的な障害、および不明なエラーが明確に区別されているか。
  • フィールドレベルのエラー、追跡可能なインスタンス、および制御された拡張メンバーを設計しているか。
  • スタックトレース、内部ID、個人データ、信頼できない生の例外の露出を避けているか。

最初に確認すべき明確化の質問

クライアントが機械的な判定を必要としているのか、それとも表示用テキストのみでよいのか、ローカライゼーション、一括バリデーション、非同期ジョブが存在するか、タイプがサービス間で共有されているか、どの状態がリトライ可能か、そしてゲートウェイ、サービス、クライアントがそれぞれ何をログに記録し、表示し、リクエストの関連付けに使用するかを確認します。

30秒での回答構成

安定した基盤として、application/problem+jsontypetitlestatusdetailinstanceを組み合わせて使用します。コード、フィールドパス、リトライ時間、ドキュメントバージョンのための制御された拡張を追加します。HTTPステータスは一般的なセマンティクスを担い、typeはプログラム可能なカテゴリを担います。内部の原因はログに残し、レスポンスには安全でアクション可能な情報を含めます。

深掘りした回答

1. ステータスとタイプの境界を確立する

構文エラーまたは一般的なリクエストの失敗には400、認証の欠如には401、認識されたが許可されていないリクエストには403、リソースが見つからない場合は404、現在の状態との競合には409、レート制限には429、サーバーまたは依存関係の障害には5xxを使用します。typeは安定した文書化されたURIにします。クライアントは変動しやすいtitleやdetailのテキストをパースすべきではありません。

2. Problem Detailsフィールドの設計

typeは問題を分類し、titleは人間が読める安定した概要であり、statusはレスポンスを反映し、detailはこのリクエストを説明し、instanceはこの発生を一意に識別します。拡張には、語彙と長さを制限した上で、コード、フィールドパス、パラメータ名、リトライ時間、またはドキュメントバージョンを含めることができます。一括バリデーションでは、各項目が入力位置を指し示す配列を返すことができます。

3. バリデーション、競合、およびリトライの処理

バリデーションの失敗は、フィールドの修正方法をクライアントに伝えるべきであり、リトライを要求すべきではありません。競合には再読み込みまたは別のビジネスアクションが必要です。429または一時的な依存関係の障害にはRetry-Afterを含めることができますが、クライアント側でもバックオフと試行制限が必要です。膨大な200レスポンスからクライアントに推測させるのではなく、リトライ可能性を明示してください。

4. セキュリティとプライバシーの境界を保護する

スタックトレース、SQL、キー、内部ホスト名、テナントをまたぐ詳細、または完全な個人レコードを含めてはなりません。detailにはアクション可能な事実のみを記述し、instanceは予測不可能な、または制御された参照である必要があります。内部ログの生の例外とリクエストIDを関連付けます。認証エラーでのアカウント列挙の漏洩を防ぎ、権限によってフィールドエラーをフィルタリングします。

5. サービス間およびバージョン間での進化

共有タイプ、ステータス、拡張はバージョン管理されたドキュメントとコントラクトテストに配置します。ゲートウェイがサービスのセマンティクスを書き換えるべきではありません。フィールドは互換性を保って追加し、廃止予定のタイプには移行期間を設けます。クライアントは未知のタイプに対してステータスと安全なdetailにフォールバックする必要があります。タイプの分布、リトライの成功率、フィールドエラーの多発箇所、リクエストIDの追跡可能性を監視します。

優れた回答例

すべてのエラーを、安定したtype URI、title、status、detail、instanceを持つapplication/problem+jsonとして宣言します。HTTPセマンティクスによって400/401/403/404/409/429および5xxを区別します。バリデーション用にはフィールドパスと安全なコードを追加し、レート制限または一時的な依存関係の障害用にはRetry-Afterを追加します。クライアントは、変動しやすいdetailをパースするのではなく、typeを使用して修正、再取得、バックオフ、サポートへの問い合わせのいずれを行うかを決定します。内部ログにはスタックトレース、依存関係の状態、リクエストIDが保持され、レスポンスからはSQL、キー、テナントデータ、個人レコードが除外されます。バージョン管理されたタイプとコントラクトテストにより、サービス間の進化を保護します。未知のタイプはステータスにフォールバックします。リリース後は、エラータイプ、リトライ結果、フィールドのホットスポットを監視します。

よくある間違い

  • すべてのエラーに対して200と文章を返し、クライアントがプログラムで判断できないようにしてしまうこと。
  • クライアントをtitleやdetailの文字通りの言い回しに依存させ、翻訳によって動作が破綻すること。
  • バリデーション、競合、レート制限、一時的な障害に500というラベルを付けること。
  • detail内にスタックトレース、SQL、内部ホスト名、または完全なユーザーデータを返すこと。
  • 内部の例外クラス名を公開タイプとして露出し、実装の詳細をコントラクトに固定してしまうこと。
  • 未知のタイプのフォールバックやサービス間のコントラクトテストが存在しないこと。

フォローアップ質問

typeはアクセス可能なURLである必要がありますか?

安定したURIであるべきであり、説明ドキュメントを指していても構いませんが、クライアントが処理のためにネットワークリクエストを必要とするべきではありません。重要な特性は、セマンティックな同一性、バージョン管理、および移行ガイダンスです。

detailはローカライズすべきですか?

機械可読フィールドとtypeは安定した状態に保ち、ユーザー向け文言は言語とコンテキストに合わせてクライアント側でレンダリングします。サーバーがdetailを返さなければならない場合は、安全なテンプレートと言語ネゴシエーションを使用します。未翻訳の内部例外を決して露出させないでください。

ゲートウェイはすべてのエラーを書き換えるべきですか?

リクエストID、タイムアウトエラー、プロトコルレベルの障害を追加することはできますが、ビジネスタイプは保持する必要があります。書き換えにはバージョン管理されたルールと可観測性が必要です。そうでなければ、クライアントには実際の原因と一致しないセマンティクスが見えることになります。

バッチリクエストにおける部分的な成功はどのように処理しますか?

項目ごとのステータス、入力位置、リトライ可能性を持つバッチ結果を定義し、全体のHTTPステータスが何を意味するかを明記します。曖昧なdetailでは部分的な成功を表現できません。また、クライアントはすでに成功した項目を再送信してはなりません。

公開情報ソース

関連する質問