Come rappresentare i riferimenti agli oggetti in JSON?

4

Sto cercando di capire quale sia l'approccio migliore quando si gestiscono i riferimenti agli oggetti in un JSON da inviare al mio server per la deserializzazione.

Per chiarire, ciò che intendo è come fare riferimento ai dati contenuti nel corpo JSON stesso.

Per l'esempio, utilizziamo il seguente (non corretto) corpo 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 ],
    },
  ]
}

Ho bisogno di alcuni mezzi per riferirsi a quei playerX , che rappresenterebbero i giocatori inviati nella lista giocatori (Giocatore 1, Giocatore 2, ecc ...), come puoi immaginare.

Posso pensare a tre diversi modi per farlo e nessuno mi soddisfa:

Il primo modo è semplicemente riferirsi al giocatore come alla sua posizione nell'elenco giocatori , in questo modo non sono necessarie ulteriori informazioni nel corpo JSON. Ad esempio, se avessimo "teams": [ [ 0, 1 ], [ 2, 3 ] ] , vorremmo dire che abbiamo due squadre, la prima composta da P1 e P2 e la seconda da P3 e P4.

Gli altri due modi utilizzerebbero entrambi gli ID (avrei bisogno di implementare un sistema di ID per i miei giocatori, dal momento che finora non ho avuto bisogno di ID). Tuttavia, poiché i giocatori non esistono ancora nel sistema, i loro ID sono sconosciuti. Come vedo, possiamo fare due cose:

Possiamo inviare esplicitamente gli ID giocatore al server, ma dovremmo sviluppare modi per preservare l'unicità dell'ID. Preferirei che questi non venissero gestiti dall'utente, a dire il vero, oltre che essere autogenerati. Il modo in cui rappresenteremmo i giocatori nella lista squadre sembrerebbe lo stesso della prima scelta in formato, ma invece delle posizioni avremmo 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 seconda opzione è più sicura in termini di generazione ID, ma richiede due passaggi. Per prima cosa inviamo i dati del giocatore al server, quindi l'utente può chiedere al server le informazioni sui giocatori e controllare i loro ID. In questo modo creano i team in modo sicuro perché l'ID è stato generato dal server.

Passaggio 1. Invia giocatori.

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

Passaggio 2. Interrogare i giocatori. GET /players

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

Passaggio 3. Invia team.

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

Quindi, come viene solitamente trattato? In che modo gli sviluppatori di API JSON affrontano questo scenario?

    
posta dabadaba 10.06.2016 - 18:58
fonte

3 risposte

3

Per ispirazione, potresti voler esaminare alcune delle API di json (ad esempio: json api , HAL ) gestisci l'incorporamento.

Una semplice risposta è tracciare i tuoi dati in un archivio di valori chiave. Ad esempio

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

E poi descrivi i giocatori assegnati al tuo team usando i riferimenti locali

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

Come succede, questo schema copre il caso in cui si hanno anche identificatori. O dove hai solo alcuni identificatori

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

Ci sono versioni più elaborate di questa idea (vedi i link).

Detto questo , sono stato su questa strada da solo, e mi sono davvero legato in nodi fino a quando ho concluso: se quello che hai veramente è una lista di nomi, piuttosto che una lista di giocatori ammettilo a te stesso, codificalo in quel modo e affrontalo. È il modo più onesto di rappresentare ciò che accade nel dominio in quel momento.

In questo caso, il payload del tuo messaggio dovrebbe apparire molto vicino a:

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

Se questo ti rende nervoso, ricorda: questa non è una descrizione dei tuoi oggetti di dominio; è un messaggio . Le modifiche apportate al tuo dominio sono un effetto collaterale. Jim Webber tratta questo nell'introduzione a questo discorso .

    
risposta data 11.06.2016 - 07:44
fonte
3

Questa è davvero una bella domanda.

Il problema si presenta perché si modellano le informazioni ridondanti e si tenta di evitare la ridondanza allo stesso tempo.

Da un lato, hai un collection di player s

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

D'altra parte, hai un colletion di teams , che a sua volta consiste di sottoinsiemi da players .

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

Questo dà una composizione:

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

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

data = {players:players, teams:teams}

Guarda qui Fiddle e guarda il risultato.

Come vedi, i riferimenti causano informazioni ridondanti in JSON.stringify , perché hai ridondanti informazioni nel tuo oggetto dati.

Il problema della riduzione della ridondanza si verifica quando si inviano dati al server.

Fai un passo indietro.

Che cosa vuoi dire al server?

a) Qui hai un elenco di team, ti preghiamo di conservarlo per me. Torno più tardi Oh, a proposito, i team contengono i seguenti giocatori blablabla

b) qui hai una lista di giocatori. Tienili al sicuro per me. Ho bisogno di loro in seguito per creare "squadre".

Il tuo modello mostra che non sei chiaro.

Esistono diversi casi d'uso:

I) Voglio creare nuovi giocatori

IIa) Voglio creare nuovi team

IIb) Voglio mettere i giocatori nei team

I) In un contesto REST, potresti rilasciare un POST a /players .

IIa, b) tu POST a /teams la tua collezione di teams .

Come affrontare la situazione, che vuoi salvare richieste e non emettere un singolo POST per ogni creazione di un nuovo giocatore (e uno aggiuntivo per l'invio della squadra)?

Vorrei andare per il seguente:

Hai una collezione di giocatori: alcuni hanno un id , a indicare che erano già persistenti; alcuni di loro no.

Se crei teams , emetti solo una richiesta di POST con i team, contenente gli oggetti full player.

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

Il server non è interessato a conoscere esplicitamente quanti giocatori ci sono: è implicitamente chiaro: è la somma di tutti i giocatori (che potrebbe essere la somma di tutti i giocatori di tutte le squadre).

Il server deve capire come mantenere i giocatori e come impostare foreign keys (nel caso di DB relazionali).

    
risposta data 11.06.2016 - 17:56
fonte
0

Nel tuo esempio potresti anche avvolgere i giocatori.

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

E se dici che players e teams devono essere separati perché rappresentano entità indipendenti e i giocatori non sono solo una proprietà intrinseca di una squadra, devi quindi separare il post del giocatore.

Hai taggato il resto. Se consideri un giocatore come una risorsa unica, in realtà richiede un proprio URI.

A resource is anything that’s important enough to be referenced as a thing in itself (s)

L'utente del tuo software probabilmente vorrà eseguire operazioni CRUD su uno o più giocatori. Direi che è abbastanza chiaro che è necessario effettuare due chiamate http separate come descritto al punto 3.

    
risposta data 19.12.2017 - 00:15
fonte

Leggi altre domande sui tag