About

This post documents how Go's encoding/json can be used to parse JSON into a Go struct with the help of the Unmarshal function. We're going to make it a little more useful by using generics as well.

Schema

Payload

{
  "ok": true,
  "errors": [],
  "data": { "pages": 123 } | { "color": "blue" }
}

Response

type Response[T any] struct {
  Ok     bool     `json:"ok"`
  Errors []string `json:"errors"`
  Data   T        `json:"data"`
}

Experiment

Overview

Our experiment sets up two examples with slightly different payloads. The first payload includes a book with a page count, and the second payload includes a car with a color. The unmarshal function is used to parse the JSON into a Go struct, and, if successful, the struct is initialized with the data from the JSON.

One word before we begin though, json.Unmarshal expects a []byte. If your JSON comes from an io.Reader (file, network, or stream), use json.Decoder instead, it can read directly from the stream without buffering the entire input in memory. Otherwise the information in this post still applies:

Book

package main

import (
  "encoding/json"
)

type Response[T any] struct {
  Ok     bool     `json:"ok"`
  Errors []string `json:"errors"`
  Data   T        `json:"data"`
}

type Book struct {
  Pages int `json:"pages"`
}

func main() {
  var res Response[Book]
  str := `{"ok": true, "errors": [], "data": {"pages": 123}}`
  err := json.Unmarshal([]byte(str), &res)
  if err != nil {
    panic(err)
  }
  book := res.Data
  println(book.Pages) // 123
}

Car

package main

import (
  "encoding/json"
)

type Response[T any] struct {
  Ok     bool     `json:"ok"`
  Errors []string `json:"errors"`
  Data   T        `json:"data"`
}

type Car struct {
  Color string `json:"color"`
}

func main() {
  var res Response[Car]
  str := `{"ok": true, "errors": [], "data": {"color": "blue"}}`
  err := json.Unmarshal([]byte(str), &res)
  if err != nil {
    panic(err)
  }
  car := res.Data
  println(car.Color) // blue
}

Explanation

This explanation also applies to the car example, but we'll just talk about the book example for simplicity:

Conclusion

It is well worth mastering how to parse JSON in Go, and that's the main reason for writing this post, even though the code is pretty straightforward, writing about it is a great way to solidify the knowledge. The use of generics is a nice bonus.