web-dev-qa-db-ja.com

APIエラーの処理

私は3つの部分で機能するショップシステムを構築しています。顧客が注文を行ったり、製品を表示したりするために使用するモバイルアプリ(Android/iOS)、マネージャーが注文を管理して買い物をするために使用するデスクトップアプリケーションです。モバイルとデスクトップの両方のアプリケーションが通信するAPIを備えたWebサーバー。

サーバーAPIは落ち着いていますが、いくつかの問題が発生し始めています。ユーザーが入手できなくなったアイテムを購入しようとすると、BadRequestを返送して「注文を完了できませんでした。もう一度やり直してください」という理由を伝え、カートにある商品が利用できないことを伝える必要があります。これにより、モバイルアプリはカートから削除する商品を認識できます。すべての場所で Dto sを使用することで修正されましたが、他の問題が発生し始めました。ユーザーが配信アドレスを追加しようとして、一部のフィールドが無効な場合、BadRequestを送信できませんいくつかの文字列メッセージです。どのフィールドが無効かを正確に伝える必要があります。

そのため、すべてのエンドポイントでエラーが発生する可能性のある列挙型を作成することを考えましたが、それを行うための体系的な方法を考えることはできません。すべてのエンドポイントに可能なすべてのDtoがすでにあるので、各エンドポイントの列挙型をDtos内に配置する必要がありますか?または、それ専用の別のフォルダー/名前空間で、すべての列挙型をエンドポイントの対応するクラス内に配置しますか?私はそれのための単一の静的クラスが良いアプローチになるとは思いません。

2

説明している種類の検証はビジネスドメインの一部であり、APIエラー(適切なパラメーターを持たないリクエストなど)とは異なる方法で処理する必要があります。このように考える場合、列挙型はAPI呼び出しの結果ではなくビジネスオペレーションの結果を表すため、DTO内に列挙型を配置することは理にかなっています(すでにHTTPステータスコードがあります)。

ここで実行できる検証には2つのレベルがあります。

  • 実際に注文する際の必須の検証。これが成功し、応答で注文IDなどを返すか、失敗して失敗の理由と追加の詳細(利用できなくなったアイテムなど)を返します。
  • 別のAPI呼び出しを介して実行されるオプションの検証。これにより、注文を行う前に早い段階でフィードバックを提供できるため、ユーザーエクスペリエンスを向上させることができます。もちろん、リクエストがまだ有効であることを確認するために、注文が実際に行われたときに検証する必要があります。
3
casablanca

エラーが発生したAPI呼び出しに対して検証応答を送信しないでください。

それらを例外として扱います。あなたはメッセージとタイプを送ることができますが、それはあなたのたくさんです。

代わりに、検証自体を行うために必要なAPIをクライアントに提供します。たとえば、注文を送信して「item x is out of stock」を取得する代わりに、注文前に在庫レベルを確認するために呼び出すことができる在庫確認APIを提供します。

アドレスなどを使用して、有効なリクエストを毎回作成するために必要なルールをクライアントに提供します。文字列の古いコレクションを起動して、サーバーに同じルールを実行させないでください。

-

デビッドが彼のコメントで指摘しているように、チェックが古くなる可能性があるため、コマンドの前にチェックすべきではないという別の(間違った)ビューがあります。

ただし、実際にはデータベースレベルの構造化エラー応答が必要になるため、これは複雑なチェックでは機能しません。つまり、注文を挿入しようとしたときのFK制約などにより、在庫レベルのエラーが発生します。

これにより、ユーザーにすぐに返送され、バスケットの商品5が在庫切れであることをどういうわけか伝えます。

しかし、FK制約の失敗から公開された十分な情報がないため、その詳細レベルを設定できません。別のチェックが必要です。

答えは、私はチェックとコマンドをトランザクションにラップし、チェックが古くならないように注文を出す間データベースをロックするか、チェックが失敗した場合に部分的な注文ができないようにロールバックすることです。配置されます。

ただし、そのトランザクションスコープをクライアントに拡張することは完全に可能です。この場合、注文のために在庫を予約するという概念があります。

ほとんどの場合、これは望ましくありません。チェックが古くなっているEdgeのケースに対処し、コマンドが単純なItemOutOfStockExceptionで失敗した後にチェックを再実行する方が簡単です。

さらに、クライアントは通常wantsとにかくチェックを最初に実行します。つまり、バスケットに入れようとしているアイテムを表示しているときに、在庫があるかどうかを確認します。

1
Ewan

私が使用するサーバー応答には

  • textual-error-code、(つまり "err0815")
  • エンドユーザーには表示されず、ログファイルに追加される技術的なエラーメッセージ(つまり、「データベースのハードドライブにスペースが残っていません」)
  • エンドユーザーに表示されるローカライズされたエラーメッセージ。 (例:「技術的な問題により注文を処理できません)
  • エンドユーザーができることのローカライズされたヒント(つまり、後で再試行してください)

textual-error-codeではなくerror-enumsを使用している場合は、クライアントソフトウェアとサーバーソフトウェアを同じバージョンにコンパイルする必要があります。

クライアントがまだ知らない新しいエラー列挙型をサーバー側で発明した場合(つまり、古いAndroidアプリのバージョン))、クライアントがクラッシュする可能性があります。

1
k3b