it-swarm.com.de

Wie werden Objektreferenzen in JSON dargestellt?

Ich versuche herauszufinden, wie ich am besten mit Objektreferenzen in einem JSON umgehen kann, die zur Deserialisierung an meinen Server gesendet werden sollen.

Zur Verdeutlichung meine ich, wie auf Daten verwiesen wird, die im JSON-Body selbst enthalten sind.

Verwenden Sie für das Beispiel den folgenden (falschen) JSON-Body:

{
  "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 ],
    },
  ]
}

Ich brauche einige Mittel, um auf diese playerX zu verweisen, die die Spieler darstellen würden, die in der player -Liste (Player 1, Player 2 usw.) gesendet wurden, so gut Sie können vorstellen.

Ich kann mir drei verschiedene Möglichkeiten vorstellen und keine befriedigt mich:

Die erste Möglichkeit besteht darin, den Spieler einfach als seine Position in der Liste Spieler zu bezeichnen. Auf diese Weise werden keine zusätzlichen Informationen im JSON-Text benötigt. Wenn wir zum Beispiel "teams": [ [ 0, 1 ], [ 2, 3 ] ] Hätten, würden wir zwei Teams haben, das erste aus P1 und P2 und das zweite aus P3 und P4.

Die beiden anderen Möglichkeiten würden beide IDs verwenden (ich müsste ein ID-System für meine Spieler implementieren, da ich bisher keine IDs benötigt habe). Da die Spieler jedoch noch nicht im System vorhanden sind, sind ihre IDs unbekannt. Wie ich sehe, können wir zwei Dinge tun:

Wir können die Spieler-IDs explizit an den Server senden, müssten jedoch Methoden entwickeln, um die Eindeutigkeit der ID zu erhalten. Ich würde es vorziehen, wenn diese nicht vom Benutzer behandelt würden, um ehrlich zu sein, sowie automatisch generiert. Die Art und Weise, wie wir die Spieler in der Teams Liste darstellen würden, würde genauso aussehen wie die erste Wahl im Format, aber anstelle der Positionen hätten wir das 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 ] 
  ]
}

Die zweite Option ist in Bezug auf die ID-Generierung sicherer, erfordert jedoch zwei Schritte. Zuerst senden wir die Spielerdaten an den Server, dann kann der Benutzer den Server nach den Spielerinformationen fragen und deren IDs überprüfen. Auf diese Weise erstellen sie die Teams sicher, da die ID vom Server generiert wurde.

Schritt 1. Spieler senden.

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

Schritt 2. Spieler abfragen. GET /players

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

Schritt 3. Senden Sie Teams.

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

Wie wird das normalerweise behandelt? Wie gehen JSON-API-Entwickler mit diesem Szenario um?

11
dabadaba

Zur Inspiration möchten Sie vielleicht untersuchen, wie einige der auf json basierenden APIs (z. B. json api , HAL ) damit umgehen Einbetten.

Eine einfache Antwort besteht darin, Ihre Daten in einem Schlüsselwertspeicher zu verfolgen. Zum Beispiel

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

Und dann beschreiben Sie die Ihrem Team zugewiesenen Spieler anhand lokaler Referenzen

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

Dieses Schema deckt zufällig den Fall ab, in dem Sie auch Kennungen haben. Oder wo Sie nur einige Bezeichner haben

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

Es gibt schickere Versionen dieser Idee (siehe die Links).

Das heißt , ich war selbst auf diesem Weg und habe mich wirklich in Knoten gefesselt, bis ich zu dem Schluss kam: Wenn Sie wirklich eine Liste von haben Namen, anstatt eine Liste von Spielern, geben das zu, codieren es so und gehen damit um. Dies ist die ehrlichere Art, darzustellen, was zu diesem Zeitpunkt in der Domäne vor sich geht.

In diesem Fall sollte die Nutzlast Ihrer Nachricht sehr ähnlich aussehen:

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

Wenn Sie dadurch nervös werden, denken Sie daran: Dies ist keine Beschreibung Ihrer Domänenobjekte. Es ist eine Nachricht . Die Änderungen, die an Ihrer Domain vorgenommen werden, sind ein Nebeneffekt. Jim Webber behandelt dies in der Einleitung zu dieser Vortrag .

7
VoiceOfUnreason

Das ist eine wirklich schöne Frage.

Das Problem tritt auf, weil Sie redundante Informationen modellieren und gleichzeitig versuchen, Redundanz zu vermeiden.

Einerseits haben Sie ein collection von players

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

Auf der anderen Seite haben Sie ein colletion von teams, das selbst aus Teilmengen von players besteht.

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

Dies ergibt eine Zusammensetzung:

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

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

data = {players:players, teams:teams}

Suchen Sie hier nach dem Geige und sehen Sie sich das Ergebnis an.

Wie Sie sehen, verursachen die Referenzen redundante Informationen in JSON.stringify, Da Ihr Datenobjekt redundant Informationen enthält.


Das Problem der Vermeidung Redundanz tritt beim Senden von Daten an den Server auf.

Geh einen Schritt zurück.

Was möchten Sie dem Server mitteilen?

a) Hier haben Sie eine Liste von Teams, bitte behalten Sie sie für mich bei. Ich komme später auf dich zurück. Oh, übrigens, die Teams enthalten die folgenden Spieler blablabla

b) Hier haben Sie eine Liste der Spieler. Bewahre sie für mich auf. Ich brauche sie später, um Teams aufzubauen.

Ihr Modell zeigt, dass Sie nicht klar sind.

Es gibt mehrere Anwendungsfälle:

I) Ich möchte neue Spieler erstellen

IIa) Ich möchte neue Teams erstellen

IIb) Ich möchte Spieler in Teams einteilen

I) In einem REST-Kontext könnten Sie ein POST an /players Ausgeben.

IIa, b) Sie POST zu /teams Ihrer Sammlung von teams.

Wie Sie mit der Situation umgehen, dass Sie speichern Anfragen stellen möchten und nicht für jede Erstellung eines neuen Spielers ein einziges POST ausgeben (und ein zusätzliches für die Übermittlung des Teams) )?

Ich würde für Folgendes gehen:

Sie haben eine Sammlung von Spielern: Einige von ihnen haben ein id, was darauf hinweist, dass sie bereits bestehen geblieben sind; Einige von ihnen tun es nicht.

Wenn Sie teams erstellen, geben Sie nur eine POST Anfrage an die Teams aus, die die Spielerobjekte full enthält.

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

Der Server ist nicht daran interessiert, explizit zu wissen wie viele Spieler es gibt: es ist implizit klar: Es ist die Summe aller Spieler (was die Summe sein könnte aller Spieler in allen Teams).

Der Server muss herausfinden, wie die Spieler bestehen bleiben und wie foreign keys Festgelegt wird (bei relationalen DBs).

4
Thomas Junk

In Ihrem Beispiel könnten Sie auch die Spieler einwickeln.

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

Und wenn Sie sagen, dass players und teams getrennt werden sollten, weil sie unabhängige Einheiten darstellen und Spieler mehr als nur eine inhärente Eigenschaft eines Teams sind, müssen Sie den Spielerbeitrag trennen.

Du hast Rest markiert. Wenn Sie einen Spieler als eine einzigartige Ressource betrachten, benötigt er tatsächlich eine eigene URI.

Eine Ressource ist alles, was wichtig genug ist, um als eigenständige Sache bezeichnet zu werden ( s )

Der Benutzer Ihrer Software möchte wahrscheinlich CRUD-Operationen auf einem oder mehreren Playern ausführen. Ich würde sagen, es ist ziemlich klar, dass Sie zwei separate http-Aufrufe durchführen müssen, wie Sie in Schritt 3 beschrieben haben.

0
phil294