Conversione da JSON a struttura Go

Incollando un oggetto o un vettore JSON, genera automaticamente la corrispondente definizione di struttura Go con le relative etichette json.

Trasformare il JSON in strutture Go

Ricevere la risposta di un'API in Go comporta lo scrivere una struttura corrispondente al JSON, corredata delle sue etichette json. Con una manciata di campi non è faticoso, ma non appena l'annidamento si fa profondo, percorrere la gerarchia inventando nel frattempo i nomi dei tipi diventa il lavoro stesso. Questo strumento genera l'intero corredo di definizioni, strutture annidate comprese, dal solo JSON che incollate.

Tenete però presente che ciò che ne esce è un tipo dedotto da un solo campione. Le chiavi che non vi comparivano mancheranno, com'è naturale, e ogni campo il cui valore fosse null diventa interface{}, giacché Go non ha un primitivo annullabile su cui farlo cadere. Quando tutti gli elementi di un array sono oggetti, le loro chiavi vengono fuse in un'unica struttura e quelle presenti solo in alcuni elementi ricevono omitempty. Fare di quell'uscita una struttura da produzione presuppone che confrontiate queste deduzioni con la specifica vera dell'API e le correggiate.

Come convertire

  1. Incollate il JSON Va bene un oggetto come un array; la risposta di un'API si inserisce così com'è arrivata.
  2. Date un nome al tipo radice All'inizio si chiama Root. I nomi dei tipi annidati si ricavano da sé, convertendo ciascun nome di proprietà nella notazione Pascal.
  3. Rivedete le strutture generate Le definizioni compaiono nell'ordine dei livelli, con le etichette json già al loro posto.
  4. Copiate e rifinite Passate il risultato a gofmt, poi tornate su ciò che è diventato interface{} o su ciò che andrebbe reso puntatore, seguendo la specifica vera.

Consigli per sfruttarlo al meglio

  • Se tutti gli elementi di un vettore sono oggetti, le loro chiavi vengono fuse in un'unica struttura; alle chiavi presenti soltanto in alcuni elementi si aggiunge automaticamente l'opzione omitempty.
  • Il nome del tipo radice, inizialmente «Root», si può cambiare a piacere. I nomi delle strutture annidate sono generati automaticamente convertendo in maiuscole iniziali il nome della proprietà.
  • Il valore null del JSON diventa interface{}, perché Go non dispone di tipi elementari annullabili. Se vi occorre un trattamento rigoroso, valutate la sostituzione con un tipo puntatore.
  • Il risultato è prodotto con una formattazione semplice a rientri allineati; passandolo poi attraverso gofmt lo uniformerete allo stile del vostro progetto.
  • Incollando senz'altro un JSON di esempio preso da una risposta reale, otterrete in un attimo una prima stesura della struttura Go per le risposte.

Quando torna utile

Nell'avviare un client di API

Incollando la risposta d'esempio della documentazione avete subito una prima bozza della struttura ricevente.

Nel caricare un file di configurazione

Quando le impostazioni stanno in JSON, il loro assetto si trascrive direttamente in un tipo.

Nel decifrare la specifica altrui

Un JSON profondamente annidato si coglie assai meglio una volta disteso come insieme di strutture.

Nel preparare dati di prova

Ricavare prima i tipi da una risposta reale riduce il rischio di equivoci quando si scriveranno i sostituti.

Termini della corrispondenza dei tipi in Go

Struttura
Il tipo di Go che raccoglie più campi. Corrisponde a un oggetto del JSON.
Etichetta json
L'annotazione posta dopo un campo nella forma json:"user_id", che dice al codificatore come il nome del campo Go si allinei alla chiave del JSON.
Omitempty
Opzione dell'etichetta json che lascia il campo fuori dall'uscita quando il suo valore è il valore zero. Non significa che il campo accetti il nullo, distinzione che conviene tenere a mente.
Interface{}
Tipo che accoglie qualunque valore. I nulli del JSON e i campi dal tipo mutevole atterrano qui, il che ne fa un comodo segnale dei punti da rivedere dopo la generazione.
Notazione Pascal
L'uso di rendere maiuscola l'iniziale di ogni parola, come in UserId. In Go quella maiuscola iniziale porta anche il senso di essere esportata fuori dal pacchetto.
Tipo puntatore
Un tipo scritto *string. Vi si ricorre quando l'assenza di un valore va distinta da una stringa vuota.

Domande frequenti

Scriverle a mano espone a errori nella conversione dei nomi dei campi e a dimenticanze nelle etichette json, e con oggetti profondamente annidati richiede molto tempo. La generazione automatica previene questi errori e abbrevia sensibilmente la realizzazione.

Le chiavi JSON, scritte con i trattini bassi o con le maiuscole interne, sono convertite in maiuscole iniziali per ottenere nomi di campo esportabili in Go. La chiave originaria resta comunque nell'etichetta json, nella forma json:"chiave originaria", cosicché codifica e decodifica funzionano senza problemi. Alle chiavi che iniziano con un carattere privo di forma maiuscola, come il testo giapponese, si antepone Field (ad esempio 名前 diventa Field名前), e alle chiavi che dopo la conversione avrebbero lo stesso nome (come user_id e userId) si aggiunge un numero progressivo, così che il risultato compili sempre con nomi univoci.

I valori nulli diventano di tipo interface{}. Alle chiavi presenti soltanto in alcuni elementi di un vettore si aggiunge automaticamente l'opzione omitempty nell'etichetta json, ma poiché il tipo Go assume comunque il proprio valore nullo, valutate all'occorrenza la sostituzione con un tipo puntatore.

Se il numero nel JSON è scritto con un separatore decimale o un esponente (1.0, 1e3) si assegna float64; se non ha né l'uno né l'altro si assegna int. Il pacchetto encoding/json di Go non può decodificare in un tipo intero un numero con separatore decimale o esponente, ed è per questo che si distinguono così. Gli interi fuori dall'intervallo di un int a 64 bit (circa ±9,2×10^18) diventano float64, perché la decodifica non fallisca. Dato che float64 arrotonda tali valori, valutate json.Number o string se dovete trattare con esattezza ID di grandi dimensioni.

Non esistendo in Go i tipi unione, quando una stessa chiave presenta tipi discordanti da un elemento all'altro si ripiega su interface{}. Il tipo effettivo va poi determinato in esecuzione con un'asserzione di tipo.
Tool-kun

A proposito — la scelta progettuale delle strutture Go e delle etichette json

Go è un linguaggio a tipizzazione statica e, nel trattare il JSON, il pacchetto standard di codifica esamina la corrispondenza fra i campi della struttura e le etichette json per svolgere codifica e decodifica. Trascrivere a mano come struttura il formato delle risposte di un'interfaccia esterna è un lavoro ripetitivo che cresce con il numero dei campi e che innumerevoli progetti in Go hanno dovuto affrontare.

Questo strumento analizza la struttura di un JSON di esempio e genera automaticamente la definizione corrispondente con le etichette json, alleggerendo quel lavoro. Fra gli strumenti dello stesso genere è noto quicktype, che genera tipi per più linguaggi; quando però si vuole soltanto incollare la risposta che si ha sotto mano e ottenere in fretta una struttura Go, la semplicità di uno strumento monofunzione ha i suoi vantaggi.

Go non offre alcun costrutto per rendere facoltativo un campo di una struttura: per i campi che nel JSON possono mancare si usa perciò l'opzione omitempty nell'etichetta oppure un tipo puntatore, come *string, per distinguere il valore nullo dall'assenza di valore. La struttura generata è soltanto una deduzione meccanica a partire dalla forma dei dati: stabilire quali campi siano annullabili e progettare in vista dei futuri cambiamenti dell'interfaccia resta un lavoro da svolgere a mano, confrontandosi con la documentazione.