web-dev-qa-db-ja.com

JSONでオブジェクト参照を表す方法は?

逆シリアル化のためにサーバーに送信されるJSONのオブジェクト参照を処理するときの最善の方法を理解しようとしています。

わかりやすく言うと、JSON本体自体に含まれるデータを参照する方法です。

この例では、次の(正しくない)JSON本文を使用します。

{
  "players": [
    { "name": "Player 1" },
    { "name": "Player 2" },
    { "name": "Player 3" },
    { "name": "Player 4" }
  ],
  "teams": [
    {
      "name": "Team 1",
      "players": [ player1, player2 ],
    },
    {
      "name": "Team 2",
      "players": [ player3, player4 ],
    },
  ]
}

私はそれらを参照するいくつかの手段が必要ですplayerX、これはplayersリスト(プレーヤー1、プレーヤー2など...)で送信されたプレーヤーを表します。想像してみてください。

私はこれを行う3つの異なる方法を考えることができ、どれも私を満足させません。

最初の方法は、単純にプレーヤーをplayersリスト内の位置として参照することです。この方法では、JSON本文に追加情報は必要ありません。たとえば、"teams": [ [ 0, 1 ], [ 2, 3 ] ]つまり、2つのチームがあり、最初のチームはP1とP2で構成され、2番目のチームはP3とP4で構成されます。

他の2つの方法はどちらもIDを使用します(これまでIDを必要としていないので、プレーヤーにIDシステムを実装する必要があります)。ただし、プレーヤーはまだシステムに存在しないため、IDは不明です。ご覧のとおり、2つのことを実行できます。

プレーヤーIDを明示的にサーバーに送信できますが、IDの一意性を維持する方法を開発する必要があります。これらがユーザーによって処理されず、正直に処理され、自動生成された方がよいと思います。 teamsリストでプレーヤーを表す方法は、フォーマットの最初の選択肢と同じように見えますが、位置ではなくIDSがあります。

{
  "players": [
    { "id": 1, "name": "Player 1" },
    { "id": 2, "name": "Player 2" },
    { "id": 3, "name": "Player 3" },
    { "id": 4, "name": "Player 4" }
  ],
  "teams": [
      [ 1, 2 ], [ 3, 4 ] 
  ]
}

2番目のオプションはID生成の点ではより安全ですが、2つのステップが必要です。まず、プレーヤーデータをサーバーに送信します。次に、ユーザーはサーバーにプレーヤー情報を要求し、IDを確認できます。この方法では、IDがサーバーによって生成されたため、チームは安全にチームを作成します。

ステップ1.プレーヤーを送信します。

{
  "players": [
    { "name": "Player 1" },
    { "name": "Player 2" },
    { "name": "Player 3" },
    { "name": "Player 4" }
  ]
}

ステップ2.プレーヤーをクエリします。 GET /players

{
  "players": [
    { "id": 11, "name": "Player 1" },
    { "id": 12, "name": "Player 2" },
    { "id": 13, "name": "Player 3" },
    { "id": 14, "name": "Player 4" }
  ]
}

ステップ3.チームを送信します。

{
  "teams": [
      [ 11, 12 ], [ 13, 14 ] 
  ]
}

これは通常どのように扱われますか? JSON API開発者はこのシナリオにどのように取り組みますか?

11
dabadaba

インスピレーションを得るために、いくつかのjsonベースのAPI(例: json api[〜#〜] hal [〜#〜] )ハンドルの方法を調べることができます埋め込み。

簡単な答えの1つは、キー値ストアでデータを追跡することです。例えば

{ "/players/0" : {...}
, "/players/1" : {...}
, "/players/2" : {...}
, "/players/3" : {...}
, "/teams/0" : {...}
, "/teams/1" : {...}
}

そして、ローカルリファレンスを使用して、チームに割り当てられたプレーヤーを説明します

, "/teams/0" :
    { refs : 
        [ "/players/0"
        , "/players/1"
        ]
    }

偶然にも、このスキームは識別子もある場合をカバーしています。または、識別子がいくつかある場合

, "/teams/0" :
    { refs : 
        [ "/players/0"
        , "/players/2ad8cabe-2f93-11e6-ac61-9e71128cae77"
        ]
    }

このアイデアにはより洗練されたバージョンがあります(リンクを参照)。

それは言った、私は自分でこの道を進んでいて、結論が出るまで本当に結び目を結んでいました:あなたが本当に持っているのがリストの場合プレーヤーのリストではなく名前を使用すると、それを自分に認め、そのようにコーディングして対処します。これは、その時点でドメインで何が起こっているかを表すより正直な方法です。

この場合、メッセージのペイロードは次のようになります。

{ "Team 1" : 
  [ "Player 1"
  , "Player 2"
  ]
, "Team 2" :
  [ "Player 3"
  , "Player 4"
  ]
}

それがあなたをぴくぴくさせる場合、覚えておいてください。これはドメインオブジェクトの説明ではありません。これはメッセージです。ドメインへの変更は副作用です。 Jim Webberが this talk の紹介でこれをカバーしています。

7
VoiceOfUnreason

これは本当にいい質問です。

この問題は、冗長な情報をモデル化すると同時に冗長性を回避しようとするために発生します。

一方で、あなたはcollection of players

players = [{"id":"1"},{"id":"2"},{"id":"3"}]

一方、colletionteamsがあり、それ自体がplayersのサブセットで構成されています。

teams = [ {"id":"1", "players": [ players[0], players[1] ]} ]

これは構成を与えます:

players = [{id:1},{id:2},{id:3},{id:4}]

teams =[ {id:1, players:[players[0], players[1]]} ]

data = {players:players, teams:teams}

Fiddle をここで探し、結果を確認します。

ご覧のとおり、データオブジェクトにredundant情報があるため、JSON.stringifyには参照が冗長な情報を生成します。


回避冗長性の問題は、データをサーバーに送信するときに発生します。

下がってください。

サーバーに何を伝えたいですか?

a)ここにチームのリストがあります。私のためにそれを保持してください。後で戻ってきます。ところで、チームにはfollowingプレーヤーblablablaが含まれています

b)ここにプレイヤーのリストがあります。安全に保管してください。 「チームを構築するために後で必要になります。

あなたのモデルは、あなたがはっきりしていないことを示しています。

いくつかのユースケースがあります:

I)新しいプレイヤーを作成したい

IIa)新しいチームを作成したい

IIb)プレイヤーをチームに入れたい

I)RESTコンテキストでは、POST/playersに発行できます。

IIa、b)POSTのコレクションをteamsから/teamsに。

saveリクエストで、新しいプレーヤーを作成するたびに1つのPOSTを発行しない(およびチームを送信するための追加の1つ)場合の対処方法は?

私は次のように行きます:

プレイヤーのコレクションがあります。一部のプレイヤーにはidがあり、すでに永続化されていることを示しています。それらのいくつかはしません。

teamsを作成する場合、POSTプレーヤーオブジェクトを含むチームに対してfullリクエストを1つだけ発行します。

[{"name":"team1", "players":[{"id":"1", "name":"player1"}, "name":"player2"}]}, ... ] // you get the idea 

サーバーは明示的に知っているプレーヤーの数に興味がありません:それはimplicitelyクリアです:すべてのプレーヤーの合計です(すべてのプレーヤーの合計である可能性があります)すべてのチーム)。

サーバーは、プレーヤーを永続化する方法とforeign keysを設定する方法(リレーショナルDBの場合)を理解する必要があります。

4
Thomas Junk

あなたの例では、プレイヤーをラップすることもできます。

{
  "teams": [
    {
      "name": "Team 1",
      "players": [ 
        { "name": "Player 1" },
        { "name": "Player 2" }
      ]
    },
    {
      "name": "Team 2",
      "players": [
        { "name": "Player 3" },
        { "name": "Player 4" }
      ]
    },
  ]
}

そして、あなたが言うなら、playersteamsは独立したエンティティを表し、プレーヤーはチームの固有のプロパティ以上のものなので、分離する必要があります。その場合、プレーヤーの投稿を分離する必要があります。

残りをタグ付けしました。プレーヤーを一意のリソースと見なす場合、実際には独自のURIが必要です。

リソースは、それ自体として物として参照されるのに十分重要なものです( s

ソフトウェアのユーザーは、おそらく1つまたは複数のプレーヤーでCRUD操作を実行したいと思うでしょう。ステップ3で説明したように、2つの別個のhttp呼び出しを行う必要があることは明らかです。

0
phil294