web-dev-qa-db-ja.com

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

いくつかの統計情報を返す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ページにテーブルとして表示することです。しかし、現在のところ、統計の一部だけが必要になる人がいないかどうかは、現時点ではわかりません。

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

9
Yann

オプション2を選びます。APIコンシューマーがsome-stats-key1読み取り可能なものに変換します。これは、おそらく彼/彼女が関心のある値のリストを持っていることを意味します(たとえば、some-stats-key1およびsome-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の消費を確認しました。

8
Glorfindel

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

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

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

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

7
user949300

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

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

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

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

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

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

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

3
gnasher729

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}
               ]
   }
]
1
K. Alan Bates