liveBook · Manning

Encoding/json

As explained in Go in Action, Second Edition

encoding/json is Go's standard-library package for encoding Go values as JSON and decoding JSON into Go values.

Go’s encoding/json package converts JSON bytes into Go values and Go values back into JSON. It is useful when a CLI needs to read a configuration file, check its structure, or produce structured output. Define a Go struct for the data, then use json.Unmarshal with the input bytes and a pointer to that struct. section 10.5.1 section 10.10

For a server configuration struct:

  • Export fields so encoding/json can access them. Use tags such as `json:"port"` to map JSON keys to Go field names. section 10.5.1
  • Use `json:"host,omitempty"` to omit an empty host when marshaling, or `json:"-"` to exclude a field. section 10.5.1
  • Check errors returned by json.Unmarshal rather than treating unparsed input as a valid configuration. section 10.5.1

Parse a configuration

A JSON configuration with `name`, `version`, `debug`, `port`, and `host` maps to a `Config` struct with corresponding string, bool, and int fields. Pass its raw bytes and `&config` to `json.Unmarshal`; a type mismatch can then be reported before the configuration is used. section 10.5.1

// UnmarshalJSON validates the Host field to ensure it is a valid URL
func (c *Config) UnmarshalJSON(b []byte) error {
    temp := struct { #1
        Name    string `json:"name"`
        Version string `json:"version"`
        Debug   bool   `json:"debug"`
        Port    int    `json:"port"`
        Host    string `json:"host"`
    }{}

    if err := json.Unmarshal(b, &temp); err != nil { #2
        return err
    }

    // Validate the Host field
    if _, err := url.ParseRequestURI(temp.Host); err != nil { #3
        return fmt.Errorf("invalid Host URL: %v", err)
    }

    *c = Config(temp) #4
    return nil
}

A custom `UnmarshalJSON` method first decodes into a temporary struct, then validates the host before assigning the result. The temporary struct keeps the method from calling itself during decoding. section 10.5.1

func (c Config) MarshalJSON() ([]byte, error) {
    // Use an anonymous struct to avoid recursion
    temp := &struct {
        Name    string `json:"name"`
        Version string `json:"version"`
        Debug   bool   `json:"debug"`
        Port    int    `json:"port"`
        Host    string `json:"host"`
    }{
        Name:    c.Name,
        Version: c.Version,
        Debug:   c.Debug,
        Port:    c.Port,
        Host:    "[REDACTED]", // Redact the host value
    }

    return json.Marshal(temp)
}

A custom `MarshalJSON` method builds a temporary value with a redacted host and passes it to `json.Marshal`, giving the output different contents from the stored configuration. section 10.5.1

How Go in Action, Second Edition covers it

How deep it goes
Works through struct tags and unmarshaling, then shows custom methods for validation and redaction.
Examples
Uses a server configuration JSON file, a tagged Config struct, host URL validation, and host redaction.
What it assumes
Assumes familiarity with Go structs, pointers, and byte slices while explaining exported fields and JSON tags.
What you can do after
Build it from scratch: decode a JSON configuration into a Go struct and customize validation or serialized output.
How it connects
Connects Go structs and struct tags to marshaling, unmarshaling, file I/O, and encoding/xml.

Also explained in

Compare how 2 books explain encoding/json →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Go in Action, Second Edition. The section links point to the parts of the book it draws on.