web-dev-qa-db-fra.com

Comment représenter les références d'objets en JSON?

J'essaie de comprendre quelle est la meilleure approche lorsqu'il s'agit de références d'objet dans un JSON à envoyer à mon serveur pour désérialisation.

Pour clarifier, ce que je veux dire, c'est comment faire référence aux données contenues dans le corps JSON lui-même.

Pour l'exemple, utilisons le corps JSON (incorrect) suivant:

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

J'ai besoin de moyens pour faire référence à ceux playerX, qui représenteraient les joueurs envoyés dans la liste joueurs (Player 1, Player 2, etc ...), comme vous pouvez imaginer.

Je peux penser à trois façons différentes de le faire et aucune ne me satisfait:

La première façon consiste simplement à désigner le joueur comme sa position dans la liste joueurs, de cette façon, aucune information supplémentaire n'est nécessaire dans le corps JSON. Par exemple, si nous avions "teams": [ [ 0, 1 ], [ 2, 3 ] ] cela voudrait dire que nous avons deux équipes, la première composée de P1 et P2 et la seconde de P3 et P4.

Les deux autres façons utiliseraient toutes deux des identifiants (je devrais implémenter un système d'identification pour mes joueurs, car jusqu'à présent je n'ai pas eu besoin d'identifiants). Cependant, comme les joueurs n'existent pas encore dans le système, leurs identifiants sont inconnus. Comme je le vois, nous pouvons faire deux choses:

Nous pouvons envoyer explicitement les identifiants des joueurs au serveur, mais nous devons développer des moyens de préserver l'unicité des identifiants. Je préférerais que ceux-ci ne soient pas gérés par l'utilisateur, par honnête, ainsi que générés automatiquement. La façon dont nous représenterions les joueurs dans la liste équipes ressemblerait au premier choix de format, mais au lieu des positions, nous aurions l'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 ] 
  ]
}

La deuxième option est plus sûre en termes de génération d'ID, mais elle nécessite deux étapes. Nous envoyons d'abord les données du joueur au serveur, puis l'utilisateur peut demander au serveur les informations des joueurs et vérifier leurs identifiants. De cette façon, ils créent les équipes en toute sécurité car l'ID a été généré par le serveur.

Étape 1. Envoyez des joueurs.

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

Étape 2. Interrogez les joueurs. GET /players

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

Étape 3. Envoyez des équipes.

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

Alors, comment cela est-il généralement traité? Comment les développeurs d'API JSON abordent-ils ce scénario?

11
dabadaba

Pour vous inspirer, vous voudrez peut-être examiner la façon dont certaines des api basées sur json (ex: json api , HAL ) encastrement.

Une réponse simple consiste à suivre vos données dans un magasin de valeurs clés. Par exemple

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

Et puis vous décrivez les joueurs assignés à votre équipe en utilisant des références locales

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

En l'occurrence, ce schéma couvre le cas où vous avez également des identifiants. Ou où vous n'avez que quelques identifiants

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

Il existe des versions plus sophistiquées de cette idée (voir les liens).

Cela dit , je suis moi-même descendu sur cette route, et je me suis vraiment attaché en nœuds jusqu'à ce que je conclus: si ce que vous avez vraiment est une liste de les noms, plutôt qu'une liste de joueurs, admettez-le vous-même, codez-le de cette façon et traitez-le. C'est la façon la plus honnête de représenter ce qui se passe dans le domaine à ce moment-là.

Dans ce cas, la charge utile de votre message doit être très proche de:

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

Si cela vous rend nerveux, rappelez-vous: ce n'est pas une description de vos objets de domaine; c'est un message . Les modifications qu'il apporte à votre domaine sont un effet secondaire. Jim Webber en parle dans l'introduction de cet exposé .

7
VoiceOfUnreason

C'est une très belle question.

Le problème se pose car vous modélisez des informations redondantes et essayez d'éviter la redondance en même temps.

D'une part, vous avez un collection de players

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

D'un autre côté, vous avez un colletion de teams, lui-même composé de sous-ensembles de players.

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

Cela donne une composition:

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

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

data = {players:players, teams:teams}

Regardez ici le Fiddle et regardez le résultat.

Comme vous le voyez, les références provoquent des informations redondantes dans JSON.stringify, car vous avez redondant informations dans votre objet de données.


Le problème de la redondance à éviter se pose lors de l'envoi de données au serveur.

Prendre du recul.

Que voulez-vous dire au serveur?

a) Ici vous avez une liste d'équipes, veuillez la conserver pour moi. Je reviens vers toi plus tard. Oh, au fait, les équipes contiennent les suivants joueurs blablabla

b) Ici vous avez une liste de joueurs. Gardez-les en sécurité pour moi. J'en aurai besoin plus tard pour constituer des équipes.

Votre modèle montre que vous n'êtes pas clair.

Il existe plusieurs cas d'utilisation:

I) Je veux créer de nouveaux joueurs

IIa) Je veux créer de nouvelles équipes

IIb) Je veux mettre les joueurs en équipe

I) Dans un contexte REST, vous pouvez émettre un POST à /players.

IIa, b) Vous POST à /teams votre collection de teams.

Comment faire face à la situation, que vous souhaitez enregistrer demandes et ne pas émettre un seul POST pour chaque création d'un nouveau joueur (et un supplémentaire pour soumettre l'équipe) )?

Je choisirais ce qui suit:

Vous avez une collection de joueurs: certains d'entre eux ont un id, indiquant qu'ils étaient déjà persistants; certains ne le font pas.

Si vous créez teams, vous émettez une seule demande POST avec les équipes, contenant les objets joueur full.

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

Le serveur n'est pas intéressé par sachant explicitement combien de joueurs il y a: c'est implicitement clair: c'est la somme de tous les joueurs (qui pourrait être la somme de tous les joueurs dans toutes les équipes).

Le serveur doit comprendre comment conserver les joueurs et comment définir foreign keys (en cas de bases de données relationnelles).

4
Thomas Junk

Dans votre exemple, vous pouvez également envelopper les joueurs.

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

Et si vous dites que players et teams doivent être séparés car ils représentent des entités indépendantes et que les joueurs sont plus qu'une propriété inhérente d'une équipe, alors vous devez séparer le message du joueur.

Vous avez marqué le repos. Si vous considérez un joueur comme une ressource unique, il nécessite en fait son propre URI.

Une ressource est tout ce qui est suffisamment important pour être référencé comme une chose en soi ( s )

L'utilisateur de votre logiciel voudra probablement exécuter des opérations CRUD sur un ou plusieurs joueurs. Je dirais qu'il est assez clair que vous devez effectuer deux appels http séparés comme vous l'avez décrit à l'étape 3.

0
phil294