È buona pratica rendere l'elenco di valori di risposta API come dizionario?

7

Ho un endpoint API che restituisce alcune statistiche. Attualmente la risposta è la seguente:

Opzione 1:

{
    "stats": [
                {
                    "name": "some-stats-key1",
                    "value": 10
                },
                {
                    "name": "some-stats-key2",
                    "value": 20
                }
            ],
    ... other keys
}

Ma questo sembra un po 'complesso e io come renderlo simile:

Opzione 2:

{
    "stats": {
                "some-stats-key1": 10,
                "some-stats-key2": 20
            }
    ... other keys
}

Capisco che l'Opzione 1 sia più facile da estendere, ma meno comoda per gli utenti. Quali altri problemi posso affrontare utilizzando una di queste opzioni? O dovrei creare una soluzione ibrida come:

Opzione 3:

{
    "stats": {
                "some-stats-key1": {
                                        "name": "some-stats-key1",
                                        "value": 10
                                    },
                "some-stats-key2": {
                                        "name": "some-stats-key2",
                                        "value": 20
                                    },
            },
    ... other keys
}

I tasti "some-stats-key1" e "some-stats-key2" sono solo valori interni e l'utente API previsto li mapperà in nomi leggibili usando la documentazione. Tutte le chiavi sono uniche.

L'ordine di "statistiche" non è importante.

Il tipico caso d'uso è solo quello di ottenere tutte le statistiche, chiavi di corrispondenza con nomi leggibili e mostrare come tabella su una pagina web. Ma al momento non posso dire se nessuno avrà bisogno solo di una parte delle statistiche più tardi.

Esiste una best practice per questo problema?

    
posta Yann 04.07.2017 - 13:51
fonte

4 risposte

8

Io opterei per l'opzione 2. Se il consumatore dell'API convertirà some-stats-key1 in qualcosa di leggibile, ciò significa probabilmente che lui / lei ha una lista di valori a cui è interessato (ad esempio, some-stats-key1 e some-stats-key3 ), e itererà su quella lista. Scegliendo un oggetto JSON, verrà deserializzato come dizionario / mappa che fornisce una comoda ricerca per il consumatore dell'API.

Ciò sarà più complicato con l'opzione 1, in cui il consumatore deve eseguire iterazioni sull'array JSON, o pre-creare il proprio dizionario con chiavi interessanti.

L'opzione 3 è un po 'troppo prolissa per me, la duplicazione dei nomi dei tasti non mi piace proprio.

Se l'estensibilità è un problema, puoi sempre pubblicare una v2 della tua API restituendo qualcosa come

"stats": {
    "some-stats-key1": { "value": 10, "error-margin": 0.1 },
    "some-stats-key2": { "value": 20, "error-margin": 0.2 }
}

e mantenere la v1 per la compatibilità all'indietro. Mantenere la retrocompatibilità con una singola versione dell'API può essere una vera PITA se non si ha il controllo completo su come l'API viene consumata. Ho visto un consumo di una mia API 'break' quando ho aggiunto una coppia di valori-chiave in più (facoltativa) (cioè non cambiando la struttura).

    
risposta data 04.07.2017 - 14:38
fonte
5

Le due opzioni hanno i classici vantaggi di Lista contro Mappa.

1) L'elenco consente voci duplicate e mantiene l'ordine. Se queste caratteristiche sono importanti, utilizza l'Elenco, anche se è più clunkier.

2) La mappa non consente duplicati. Mantenere l'ordine è possibile con un piccolo lavoro extra. Il grande vantaggio è la semplicità del formato dei dati e la ricerca di un particolare elemento è banale.

La mia scelta predefinita è sempre la mappa più semplice, ma YMMV.

    
risposta data 05.07.2017 - 23:08
fonte
3

Quando ottengo i dati da un'API, I always controlla che tutto sia come mi aspetto. Pertanto il mio tentativo di elaborare i dati consiste nella verifica e nell'elaborazione effettiva.

Nel caso 1 devo verificare: a. C'è un array. b. Tutti gli elementi nell'array sono dizionari. c. Ogni dizionario ha un "nome" chiave. d. Tutti i valori per il tasto "nome" sono unici.

Nel caso 3 devo verificare: a. C'è un dizionario. b. Tutti i valori nel dizionario sono dizionari. c. Ogni dizionario ha un "nome" chiave con un valore che corrisponde alla chiave nel dizionario esterno. Un po 'meglio.

Nel caso 2 devo controllare: a. C'è un dizionario.

(Ovviamente devo controllare anche i valori). Quindi il tuo caso 2 richiede il minimo controllo da parte mia. In realtà ottengo una struttura dati immediatamente utilizzabile.

L'unico problema con 2 è che non è estendibile. Quindi, invece di inviare il valore come un numero, potresti inviare {valore: 10} che può quindi essere esteso in un modo compatibile con le versioni precedenti.

La ridondanza è cattiva. L'unica cosa che ottiene la ridondanza è di farmi scrivere più codice e costringermi a pensare a cosa dovrei fare se i bit ridondanti non sono d'accordo. La versione 2 non ha ridondanza.

    
risposta data 05.07.2017 - 10:02
fonte
0

Da quando hai chiesto delle buone pratiche per la progettazione dell'API:

  • Non restituisco mai una risposta API contenente un oggetto al livello più alto. Tutte le chiamate di servizio restituiscono un set (come una matrice) e tale insieme contiene elementi (come istanze di oggetto). Il numero di oggetti restituiti nell'array è irrilevante per il server. Se il cliente deve prendere una decisione dal numero di articoli restituiti nella risposta, tale onere è il cliente da applicare. Se un singolo elemento è previsto, viene restituito come set di unità
  • Quando sto progettando un'API, non presumo di conoscere quale tecnologia specifica verranno utilizzati dai miei clienti API per consumare l'API, anche quando so quale tecnologia specifica è più probabile che utilizzi. La mia responsabilità è di comunicare le mie rappresentazioni di dominio in modo coerente a tutti i consumatori, non convenientemente a un particolare consumatore.
  • Se esiste un'opzione strutturale per consentire la composizione della risposta, questa struttura ha la priorità sulle opzioni che non
  • Mi sforzo di evitare di creare rappresentazioni con strutture imprevedibili.
  • Se è possibile prevedere la struttura di una rappresentazione, tutte le istanze all'interno della serie di risposte dovrebbero avere la stessa rappresentazione e il set di risposte dovrebbe essere internamente coerente.

Quindi, date le strutture che hai proposto, la struttura che implementerei sarebbe simile a questa

[
   { /* 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}
               ]
   }
]
    
risposta data 06.07.2017 - 03:45
fonte

Leggi altre domande sui tag