JSON Encoding

JSON encoding may not be commonplace in most introductions to Go (although you will almost certainly encounter it early on in writing Go programs), but it is especially important for defining and generating CustomResourceDefinitions in Kubernetes (more on this later). A few important things to keep in mind when encoding and decoding JSON bytes to structs:

  • Only exported fields will be encoded/decoded to JSON.
  • Encoding a Go type to JSON is referred to as marshaling.
  • Decoding JSON bytes to a Go type is referred to as unmarshaling.
  • Struct tags are used to manipulate JSON enconding / decoding (see examples below).
  • Unexported fields are initialized to their zero value during unmarshaling.
  • An exported field in a Go struct that is not included in the JSON that is being decoded are initialized to their zero value during unmarshaling.
  • The omitempty tag specifies that a field should be omitted from the JSON encoding if the field has an empty value, defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string.
  • The - tag specifies that a field should be omitted during both encoding and decoding.

Let's look at a few examples.

Unexported field is initialized to zero value:

package main

import (
    "encoding/json"
    "fmt"
)

// A Person has qualities of a human
type Person struct {
    First string `json:"first"`
    last  string `json:"last"`
}

func main() {
    p := &Person{}

    j := []byte(`{"first": "Ada", "last": "Lovelace"}`)
    _ = json.Unmarshal(j, p)
    fmt.Println(p.First) // prints "Ada"
    fmt.Println(p.last)  // prints ""
}

Exported field with - tag is omitted:

package main

import (
    "encoding/json"
    "fmt"
)

// A Person has qualities of a human
type Person struct {
    First string `json:"first"`
    Last  string `json:"-"`
}

func main() {
    p := &Person{}

    j := []byte(`{"first": "Ada", "last": "Lovelace"}`)
    _ = json.Unmarshal(j, p)
    fmt.Println(p.First) // prints "Ada"
    fmt.Println(p.Last)  // prints ""

    p.Last = "Lovelace"

    j, _ = json.Marshal(p)
    fmt.Println(string(j)) // prints {"first":"Ada"}
}

Encoding with omitempty tag:

package main

import (
    "encoding/json"
    "fmt"
)

// A Person has qualities of a human
type Person struct {
    First string `json:"first"`
    Last  string `json:"last"`
}

// A PersonOmit has qualities of a human
type PersonOmit struct {
    First string `json:"first"`
    Last  string `json:"last,omitempty"`
}

func main() {
    p := &Person{
        First: "Ada",
        Last:  "",
    }

    j, _ := json.Marshal(p)
    fmt.Println(string(j)) // prints {"first":"Ada","last":""}

    o := &PersonOmit{
        First: "Ada",
        Last:  "",
    }

    j, _ = json.Marshal(o)
    fmt.Println(string(j)) // prints {"first":"Ada"}
}

For further detail on the JSON package, see the official documentation.