Go Gopher How to Go

JSON (JavaScript Object Notation) is a lightweight data interchange format. Go's encoding/json package provides built-in support for encoding Go data structures to JSON and decoding JSON into Go structures. Go uses struct tags to control JSON marshaling and unmarshaling behavior.

💡 Key Points

  • Use struct tags to control JSON field names and behavior
  • Exported (capitalized) fields are included in JSON encoding
  • Use json.Marshal() to encode and json.Unmarshal() to decode
  • The omitempty tag omits zero-value fields from output
  • Use json.Encoder and json.Decoder for streaming
  • Custom marshaling can be implemented via MarshalJSON/UnmarshalJSON interfaces
  • Time values are encoded as RFC3339 strings by default

Encoding to JSON

Convert Go data structures to JSON using json.Marshal:

package main

import (
    "encoding/json"
    "fmt"
)

type Person struct {
    Name    string `json:"name"`
    Age     int    `json:"age"`
    Email   string `json:"email"`
    Address string `json:"address,omitempty"`
}

func main() {
    p := Person{
        Name:  "Alice",
        Age:   30,
        Email: "alice@example.com",
    }
    
    jsonData, err := json.Marshal(p)
    if err != nil {
        fmt.Println("error:", err)
        return
    }
    
    fmt. Println(string(jsonData))
}
Output:
{"name":"Alice","age":30,"email":"alice@example.com"}

Decoding from JSON

Parse JSON into Go structures using json.Unmarshal:

package main

import (
    "encoding/json"
    "fmt"
)

type Person struct {
    Name  string `json:"name"`
    Age   int    `json:"age"`
    Email string `json:"email"`
}

func main() {
    jsonStr := `{"name":"Bob","age":25,"email":"bob@example.com"}`
    
    var p Person
    err := json. Unmarshal([]byte(jsonStr), &p)
    if err != nil {
        fmt. Println("error:", err)
        return
    }
    
    fmt.Printf("Name: %s, Age: %d, Email: %s\n", p. Name, p.Age, p. Email)
}
Output:
Name: Bob, Age: 25, Email: bob@example.com

Working with Maps and Slices

JSON can be encoded/decoded to/from maps and slices for dynamic data:

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    // Encode slice to JSON
    colors := []string{"red", "green", "blue"}
    colorJSON, _ := json.Marshal(colors)
    fmt.Println("colors:", string(colorJSON))
    
    // Encode map to JSON
    data := map[string]interface{}{
        "name":    "Charlie",
        "active": true,
        "score":  95.5,
    }
    mapJSON, _ := json.Marshal(data)
    fmt.Println("data:", string(mapJSON))
    
    // Decode to map
    var result map[string]interface{}
    json.Unmarshal(mapJSON, &result)
    fmt.Printf("decoded: %+v\n", result)
}
Output:
colors: ["red","green","blue"]
data: {"active":true,"name":"Charlie","score":95.5}
decoded: map[active: true name:Charlie score:95.5]

Struct Tag Options

TagExampleDescription
Field Name` + "`json:\"field_name\"`" + `Sets JSON key name
omitempty` + "`json:\"field,omitempty\"`" + `Omit field if zero value
Ignore Field` + "`json:\"-\"`" + `Skip field entirely
Embedded Struct` + "`json:\",inline\"`" + `Flatten embedded struct fields
String Encoding` + "`json:\"field,string\"`" + `Encode number as string

JSON Encoding Functions

FunctionSignatureUse Case
MarshalMarshal(v interface{}) ([]byte, error)Encode to compact JSON
MarshalIndentMarshalIndent(v interface{}, prefix, indent string) ([]byte, error)Encode to formatted JSON
UnmarshalUnmarshal(data []byte, v interface{}) errorDecode JSON into struct/map
NewEncoderNewEncoder(w io.Writer) *EncoderCreate streaming encoder
NewDecoderNewDecoder(r io.Reader) *DecoderCreate streaming decoder
ValidValid(data []byte) boolCheck if JSON is valid

Type Mappings

Go TypeJSON TypeNotes
boolbooleantrue or false
int, int8, int16, int32, int64numberInteger values
uint, uint8, uint16, uint32, uint64numberUnsigned integer values
float32, float64numberDecimal values
stringstringUTF-8 encoded text
[]T, [n]TarrayArrays and slices
map[string]TobjectString keys only
structobjectField names as keys
*Tnull or valueNil pointer becomes null
interfaceanyDynamic type based on value
time.TimestringRFC3339 format

Common JSON Patterns

PatternCodeUse Case
Pretty Printjson. MarshalIndent(v, "", " ")Human-readable JSON output
Stream Encodingjson.NewEncoder(w).Encode(v)Write directly to io.Writer
Stream Decodingjson.NewDecoder(r).Decode(&v)Read from io.Reader
Partial Decodevar data map[string]json.RawMessageDecode parts of JSON later
Custom Marshalfunc (t T) MarshalJSON() ([]byte, error)Custom encoding logic
Custom Unmarshalfunc (t *T) UnmarshalJSON(data []byte) errorCustom decoding logic
Validate JSONif !json.Valid(data) { return err }Check JSON syntax
Handle Unknown Fieldsdec. DisallowUnknownFields()Strict decoding

Error Handling

Error TypeCauseSolution
SyntaxErrorInvalid JSON syntaxValidate JSON format before unmarshaling
UnmarshalTypeErrorJSON type doesn't match Go typeCheck type compatibility or use interface
UnsupportedTypeErrorCannot marshal type (e.g., chan, func)Use custom MarshalJSON or exclude field
UnsupportedValueErrorCannot encode value (e.g., NaN, Inf)Check for invalid values before encoding
InvalidUnmarshalErrorUnmarshal target is not pointerPass pointer to Unmarshal: &v