値のAPI応答リストをディクショナリとして作成することは良い方法ですか?


9

いくつかの統計情報を返すAPIエンドポイントがあります。現在、応答は次のようになります。

オプション1:

{
    "stats": [
                {
                    "name": "some-stats-key1",
                    "value": 10
                },
                {
                    "name": "some-stats-key2",
                    "value": 20
                }
            ],
    ... other keys
}

しかし、これは少し複雑に見え、私はそれをどのようにするのか:

オプション2:

{
    "stats": {
                "some-stats-key1": 10,
                "some-stats-key2": 20
            }
    ... other keys
}

オプション1は拡張が簡単ですが、ユーザーにとって快適ではないことを理解しています。これらのオプションのいずれかを使用して直面する可能性がある他の問題は何ですか?または、次のようなハイブリッドソリューションを作成する必要があります。

オプション3:

{
    "stats": {
                "some-stats-key1": {
                                        "name": "some-stats-key1",
                                        "value": 10
                                    },
                "some-stats-key2": {
                                        "name": "some-stats-key2",
                                        "value": 20
                                    },
            },
    ... other keys
}

キー「some-stats-key1」と「some-stats-key2」は単なる内部値であり、APIユーザーがドキュメントを使用して、それらを読み取り可能な名前にマッピングすることが期待されています。すべてのキーは一意です。

「統計」の順序は重要ではありません。

典型的な使用例は、すべての統計を取得し、キーを判読可能な名前と照合し、Webページにテーブルとして表示することです。しかし、現在のところ、統計の一部だけが必要になる人がいないかどうかは、現時点ではわかりません。

この問題のベストプラクティスはありますか?


1
応答の中で明示的に「stats」という名前が明示されているのはなぜですか?「統計」以外で応答しない場合は、外側のラッパーをドロップして、キーと値のペアの配列を返します。それはあなたがあなたが求める清潔さにより近づくかもしれません。
K.

5
クライアントがJSONを構造化する方法を検討してください。たとえば、AJAXを介してWebページからこのAPIを使用している場合、オプション1を使用するとArray.forEach、他のArray関数とのKey-Valueペアを簡単に反復できます。他の例では、アレイのような操作がさらに複雑になり、クライアントの生活が困難になる可能性があります
Ben Cottrell

@ K.AlanBates統計は、応答の唯一のキーではありません。更新しました。ありがとうございました。
Yann

1
エントリーの順番は重要ですか?オプション1は順序を保持します。
Roman Susi 2017

2
最も頻繁なAPIの使用例を示唆しないと、ここでベストプラクティスの答えはありません。
Roman Susi 2017

回答:


8

オプション2を選びます。APIコンシューマーがsome-stats-key1読み取り可能なものに変換する場合、おそらく彼/彼女が興味のある値のリストを持っていることを意味し(たとえば、some-stats-key1some-stats-key3)、そのリストを繰り返し処理します。JSONオブジェクトを選択することにより、APIのコンシューマーに便利なルックアップを提供するディクショナリ/マップとしてデシリアライズされます。

これは、コンシューマーがJSON配列を反復処理するか、興味深いキーを使用して独自のディクショナリーを事前に作成する必要があるオプション1では、より面倒になります。

オプション3は私には少々冗長すぎます。キー名の重複は私にとって魅力的ではありません。

拡張性が懸念される場合は、いつでもAPIのv2を公開して次のようなものを返すことができます

"stats": {
    "some-stats-key1": { "value": 10, "error-margin": 0.1 },
    "some-stats-key2": { "value": 20, "error-margin": 0.2 }
}

下位互換性のためにv1を保持します。APIの使用方法を完全に制御できない場合、APIの単一バージョン内で下位互換性を維持することは、本当のPITAになる可能性があります。追加の(オプションの)キーと値のペアを追加したとき(つまり、構造を変更しなかったとき)、「break」というAPIが消費されるのを見てきました。


3
-1「APIのv2はいつでも公開できます」。
エリックスタイン

@EricStein時間を割いてあなたの反対票を説明してくれてありがとう。投稿を編集して、これが最良の選択肢だと思う理由示しました。それでも同意しない場合は、私と申し分ありません。
Glorfindel 2017

1
公開APIのバージョン管理は簡単ではなく、簡単に行うこともできません。私はあなたの答えはあなたの好ましいアプローチを支持する議論としてそれを手放すと思います。
エリックスタイン

私見、単一バージョンとの後方互換性を維持するよりも(はるかに)簡単です。
グロルフィンデル2017

同じリソースタイプの2つのバージョンを同じ応答で返すことは、おそらく誰かがREST APIを操作することができるより悪い考えです:-/。それはあなたの例であなたが提案していることですか?
Laiv

7

2つのオプションには、従来のリストとマップの利点があります。

1)リストは重複したエントリを許可し、順序を維持します。これらの機能が重要な場合は、扱いにくいもののリストを使用してください。

2)マップでは重複を許可していません。ちょっとした手間で注文の維持が可能です。大きな利点は、データ形式がより単純であることで、特定の要素を検索するのは簡単です。

私のデフォルトの選択は常にシンプルなマップですが、YMMVです。


3

APIからデータを取得するときは、すべてが期待どおりであることを常に確認します。したがって、あなたのデータを処理する私の努力は、検証と実際の処理で構成されています。

ケース1では、以下を確認する必要があります。配列があります。b。配列内のすべてのアイテムは辞書です。c。すべての辞書にはキー「名前」があります。d。「名前」キーのすべての値は一意です。

ケース3では、以下を確認する必要があります。辞書があります。b。辞書内のすべての値は辞書です。c。各ディクショナリには、外部ディクショナリのキーと一致する値を持つキー「名前」があります。やや良い。

ケース2では、以下を確認する必要があります。辞書があります。

(もちろん、値もチェックする必要があります)。したがって、あなたのケース2は、私の側でのチェックの量が最小です。私は実際にすぐに使用できるデータ構造を取得します。

2の唯一の問題は、拡張できないことです。そのため、値を数値として送信する代わりに、{value:10}を送信することができます。これは、下位互換性のある方法で拡張できます。

冗長性が悪い。冗長性が実現する唯一のことは、より多くのコードを記述させることと、冗長ビットが一致しない場合の対処法を考えさせることです。バージョン2には冗長性がありません。


1

API設計の良い実践を求めたので:

  • トップレベルのオブジェクトを含むAPI応答を返すことはありません。すべてのサービス呼び出しは(配列として)セットを返し、そのセットには(オブジェクトインスタンスとして)要素が含まれます。配列で返されるオブジェクトの数はサーバーには関係ありません。クライアントが応答で返されたアイテムの数から判断する必要がある場合、その負担はクライアントの強制です。単一のアイテムが期待される場合、それはユニットセットとして返されます。
  • 私がAPIを設計しているとき、私がAPIを使用するために使用する可能性が最も高い特定のテクノロジーを知っている場合でも、APIクライアントがそのAPIを使用するために使用する特定のテクノロジーを知る必要はありません。私の責任は、特定の消費者に都合よくではなく、すべての消費者に一貫して私のドメイン表現を伝えることです。
  • 応答を構成できるようにする構造オプションが存在する場合、この構造は、そうでないオプションよりも優先されます。
  • 予測できない構造を持つ表現を作成しないように努めています。
  • 表現の構造を予測できる場合、応答セット内のすべてのインスタンスは同じ表現でなければならず、応答セットは内部的に一貫している必要があります。

だから、あなたが提案した構造を考えると、私が実装する構造はこれに似たものになるでしょう

[
   { /* returns only the 'common' metrics */
      "stats": [
                  {"key":"some-metric1","value":10},
                  {"key":"some-metric2","value":20}
               ]
   },
   { /* returns an optional metric in addition to the "common" metrics */
      "stats": [
                  {"key":"some-metric1","value":15},
                  {"key":"some-metric2","value":5},
                  {"key":"some-optional-metric", "value":42}
               ]
   },
   { /*returns the 'common' metrics as well as 2 candidates for "foo-bar" */
      "stats": [
                  {"key":"some-metric1", "value": 5},
                  {"key":"some-metric2", "value": 10},
                  {"key":"foo-bar-candidate", "value": 7},
                  {"key":"foo-bar-candidate", "value": 11}
               ]
   }
]

フレームワークまたはよく知られているWeb APIからの参照または例を引用して、ポイント1に従う理由について詳しく教えてください。全体的に、あなたの答えは、少なくとも一見、非常に複雑に見えます。
user949300 2017

@ user949300 ...うーん。re:overly complex私にはとてもシンプルに見えます。すべてのシリアライゼーションロジックで一貫した規則を維持するため、1番のポイントに従います。応答セットの項目数は、サービスインターフェースの実装の詳細です。セット内の「3」のアイテムを通信するには、これらの3つのアイテムを配列でラップするのが最も便利です。「1」は数字です。
K.

@ user94900 re: example from a well known web APIgoogle.com
K.

@ user94900 re: example from a frameworkANSI SQLを話すもの
K.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.