JSON in Go

Working with JSON isn't always straightforward

Luckily Go and JSON get along famously

Decoding

type GameOfThrones struct {
    Awesome  bool
    Seasons  int
    Hodor    string
}

raw := `{"awesome": true, "seasons": 5, "hodor": "Hodor"}`

got := &GameOfThrones{}
err := json.Unmarshal([]byte(raw), &got)
if err != nil {
    panic(err) // Or something more useful
}

fmt.Println(got)
// &{true 5 Hodor}
fmt.Println(got.Hodor)
// Hodor

Encoding

type GameOfThrones struct {
    Awesome  bool
    Seasons  int
    Hodor    string
}

got := &GameOfThrones{
    Awesome: true,
    Seasons: 5,
    Hodor: "Hodor"}
gotJson, err := json.Marshal(got)
if err != nil {
    panic(err)
}

fmt.Println(string(gotJson))
// {"Awesome":true,"Seasons":5,"Hodor":"Hodor"}

But note that the fields are capitalized

What if we don't want capitals?

Tags

type GameOfThrones struct {
    Awesome  bool    `json:"awesome_sauce"`
    Seasons  int     `json:"number-of-seasons"`
    Hodor    string  `json:"Hodor?"`
}

got := &GameOfThrones{
    Awesome: true,
    Seasons: 5,
    Hodor: "Hodor"}
g, _ := json.Marshal(got)

fmt.Println(string(g))
// {"awesome_sauce":true,"number-of-seasons":5,"Hodor?":"Hodor"}

What about nested fields?

Nested JSON

type User struct {
    Name      string   `json:"name"`
    Email     string   `json:"email"`
    Twitter   Twitter  `json:"twitter"`
} 

type Twitter struct {
    Id        int      `json:"id"`
    Username  string   `json:"username"`
}

raw := `{
        "name":"Hodor",
        "email":"hodor@hodor.io",
        "twitter": {"id": 123,"username": "hodor"}
    }`

user := &User{}
json.Unmarshal([]byte(raw), &user)

fmt.Println(user.Email)
// hodor@hodor.io
fmt.Println(user.Twitter.Id)
// 123

Default Values

type User struct {
    Name       string    `json:"name"`
    Age        int       `json:"age"`
    Interests  []string  `json:"interests"`
    Twitter    Twitter   `json:"twitter"`
} 

type Twitter struct {
    Id        int      `json:"id"`
    Username  string   `json:"username"`
}

user := &User{}
u, _ := json.Marshal(user)
fmt.Println(string(u))
// {"name":"","age":0,"interests":null,"twitter":{"id":0,"username":""}}

Null Values

type User struct {
    Name       *string    `json:"name"`
    Age        *int       `json:"age"`
    Interests  []string   `json:"interests"`
    Twitter    *Twitter   `json:"twitter"`
} 

type Twitter struct {
    Id        int      `json:"id"`
    Username  string   `json:"username"`
}

user := &User{}
u, _ := json.Marshal(user)
fmt.Println(string(u))
// {"name":null,"age":null,"interests":null,"twitter":null}

Omitting Fields

type Country struct {
    Name               string  `json:"name"`
    NationalDance      string  `json:"national_dance,omitempty"`
    NationalDrink      string  `json:"-"`
    nuclearLaunchCode  int  
}

russia := &Country{"Russia", "troika", "vodka", 4321}
r, _ := json.Marshal(russia)
fmt.Println(string(r))
// {"name":"Russia","national_dance":"troika"}

usa := &Country{"USA", "", "bourbon", 1234}
u, _ := json.Marshal(usa)
fmt.Println(string(u))
//{"name":"USA"}

YOLO Decoding

AKA structs are for suckas*

*not actually true

Decoding into a map

raw := `{"pi":3.14,"langs":["go","c","haskell","erlang","python"]}`

var yolo map[string]interface{}

if err := json.Unmarshal([]byte(raw), &yolo); 
err != nil {
    panic(err)
}

pi := yolo["pi"].(float64)
fmt.Println(pi)
// 3.14

langs := yolo["langs"].([]interface{})
fmt.Println(len(langs))
// 5
lang1 := langs[0].(string)
fmt.Println(lang1)
// go

Thanks!

JSON in Go

By zeroviscosity

JSON in Go

Presented at the Toronto Go Meetup 2015-03-12

  • 2,129