Leggere file JSON in Golang

Adesso sto usando Go per scrivere i miei programmi e avevo bisogno di leggere dei file JSON. Uhm.. Come si fa? Per fortuna la libreria standard di Go è molta completa e ci rende le cose piú semplice. Ecco qua come ho risolto il problema.

Questo è il mio file JSON chiamato tentacles.json

[
  {
    "name": "Purple Tentacle",
    "description": "A mutant monster and lab assistant created by mad scientist Dr. Fred Edison."
  },
  {
    "name": "Green Tentacle",
    "description": "Harmless and friendly brother of Purple Tentacle."
  },
  {
    "name": "Bernard Bernoulli",
    "description": "Green Tentacle's friend, he's a nerd with glasses."
  }
]

Adesso seguiamo la buona prassi della TDD (test-driven development) e prima di tutto scriviamo una funzione di test in json_test.go

package main

import "testing"

// TestReadJSON testing read from JSON file
func TestReadJSON(t *testing.T) {
    tentacles := getTentacles()
    tentacle := tentacles[2]
    expectedName := "Bernard Bernoulli"
    expectedDescription := "Green Tentacle's friend, he's a nerd with glasses."
    if expectedName != tentacle.Name {
        t.Errorf("Tentacle.name == %q, want %q",
            tentacle.Name, expectedName)
    }
    if expectedDescription != tentacle.Description {
        t.Errorf("Tentacle.description == %q, want %q",
            tentacle.Description, expectedDescription)
    }
}

ovviamente il test ci darà un errore perché dobbiamo ancora scrivere la funzione getTentacles().

$ go test -v
# dd-golang/json
./json_test.go:7: undefined: getTentacles
FAIL    dd-golang/json [build failed]

e questo è il programma main in json.go

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "os"
)

// Tentacle a character from Day of Tentacles
type Tentacle struct {
    Name        string `json:"name"`
    Description string `json:"description"`
}

func (t Tentacle) toString() string {
    bytes, err := json.Marshal(t)
    if err != nil {
        fmt.Println(err.Error())
        os.Exit(1)
    }
    return string(bytes)
}

func getTentacles() []Tentacle {
    tentacles := make([]Tentacle, 3)
    raw, err := ioutil.ReadFile("./tentacles.json")
    if err != nil {
        fmt.Println(err.Error())
        os.Exit(1)
    }
    json.Unmarshal(raw, &tentacles)
    return tentacles
}

func main() {
    tentacles := getTentacles()
    fmt.Println(tentacles)
    for _, te := range tentacles {
        fmt.Println(te.toString())
    }
}

Adesso il test passa senza problemi

$ go test -v
=== RUN   TestReadJSON
--- PASS: TestReadJSON (0.00s)
PASS
ok      dd-golang/json  0.002s

questo è l'output del programma

$ go run json.go
[{Purple Tentacle A mutant monster and lab assistant created by mad scientist Dr. Fred Edison.} {Green Tentacle Harmless and friendly brother of Purple Tentacle.} {Bernard Bernoulli Green Tentacle's friend, he's a nerd with glasses.}]
{"name":"Purple Tentacle","description":"A mutant monster and lab assistant created by mad scientist Dr. Fred Edison."}
{"name":"Green Tentacle","description":"Harmless and friendly brother of Purple Tentacle."}
{"name":"Bernard Bernoulli","description":"Green Tentacle's friend, he's a nerd with glasses."}

Come puoi vedere, ho usato una struct per memorizzare i dati JSON, e se hai bisogno di convertire JSON a strutture di GO, ti consiglio di andare alla pagina JSON-to-Go.

Danilo