JSON

JSON (JavaScript Object Notation) is a lightweight data-interchange format.

Example:

{
    "name": "Alice",
    "age": 30,
    "country": "Vietnam"
}

JSON is widely used for:

  • Configuration files

  • REST APIs

  • Data exchange

  • Application storage

Go provides built-in support through the encoding/json package.


Marshal: Struct → JSON

Suppose we have:

type Person struct {
    Name    string
    Age     int
    Country string
}

Create a value:

p := Person{
    Name:    "Alice",
    Age:     30,
    Country: "Vietnam",
}

Convert to JSON:

data, err := json.Marshal(p)
if err != nil {
    fmt.Println(err)
    return
}
 
fmt.Println(string(data))

Output:

{"Name":"Alice","Age":30,"Country":"Vietnam"}

MarshalIndent

For human-readable JSON:

data, err := json.MarshalIndent(
    p,
    "",
    "    ",
)

Output:

{
    "Name": "Alice",
    "Age": 30,
    "Country": "Vietnam"
}

Useful for:

  • Configuration files

  • Debugging

  • Version-controlled JSON


Unmarshal: JSON → Struct

JSON:

{
    "Title":"Go Programming",
    "Author":"John",
    "Pages":500
}

Struct:

type Book struct {
    Title  string
    Author string
    Pages  int
}

Decode:

var book Book
 
err := json.Unmarshal(data, &book)
if err != nil {
    fmt.Println(err)
    return
}

Now:

fmt.Println(book.Title)

prints:

Go Programming

Why Use &book?

json.Unmarshal() modifies the struct.

Therefore it requires a pointer.

Correct:

json.Unmarshal(data, &book)

Incorrect:

json.Unmarshal(data, book)

Without a pointer, Go only receives a copy.


Struct Tags

Default JSON field names are the exported Go field names.

type Person struct {
    Name string
}

Produces:

{
    "Name":"Alice"
}

Custom field names:

type Person struct {
    Name string `json:"name"`
}

Produces:

{
    "name":"Alice"
}

Ignoring Fields

Sensitive information should often be excluded.

type Person struct {
    Name     string `json:"name"`
    Password string `json:"-"`
}

Marshalling:

{
    Name: "Peter",
    Password: "secret",
}

Produces:

{
    "name":"Peter"
}

Password is completely omitted.


omitempty

Age int `json:"age,omitempty"`

If:

Age = 0

Output:

{}

The field is omitted.

Useful for optional configuration values.


Exported Fields Only

JSON only accesses exported fields.

Correct:

type Person struct {
    Name string
}

Incorrect:

type Person struct {
    name string
}

Result:

{}

Unexported fields are invisible outside the package, including to the JSON package.


JSON Works with []byte

Marshal() returns:

[]byte

because JSON is simply text encoded as bytes.

To display it:

fmt.Println(string(data))

To save it:

os.WriteFile("config.json", data, 0644)

No conversion is needed.


JSON Workflow

Encoding:

Struct

Marshal

[]byte

File / Network

Decoding:

File / Network

[]byte

Unmarshal

Struct

Common Beginner Mistakes

Forgetting Exported Fields

Incorrect:

type Person struct {
    name string
}

Produces:

{}

Forgetting the Pointer

Incorrect:

json.Unmarshal(data, person)

Correct:

json.Unmarshal(data, &person)

Forgetting string()

Incorrect:

fmt.Println(data)

Output:

[123 34 78 97 ...]

Correct:

fmt.Println(string(data))

Ignoring Errors

Always check:

if err != nil {
    fmt.Println(err)
    return
}

JSON parsing can fail due to invalid syntax or incompatible types.


Comparison with C++

GoC++
json.Marshal()Serialize object
json.Unmarshal()Deserialize object
Struct tagsSerialization annotations (library-specific)
json:"-"Ignore member during serialization

Session Summary

Topics covered:

  • JSON

  • Marshal()

  • MarshalIndent()

  • Unmarshal()

  • Struct tags

  • Field renaming

  • Ignoring fields

  • Exported vs unexported fields

  • JSON as []byte

Practical skills gained:

  • Converting structs to JSON

  • Parsing JSON into structs

  • Customizing JSON output

  • Excluding sensitive fields

  • Understanding how Go’s JSON package uses reflection


Key Takeaways

  • Marshal() converts Go structs into JSON.

  • Unmarshal() converts JSON into Go structs.

  • MarshalIndent() produces readable JSON.

  • Unmarshal() requires a pointer because it modifies the destination.

  • JSON only accesses exported fields.

  • Struct tags customize JSON field names and behavior.

  • Marshal() returns []byte, making it easy to write directly to files or send over a network.


Mental Model

Go Struct


 Marshal()


  JSON []byte


 File / Network


Unmarshal()


Go Struct

Next Topics

The core Go language has now been covered.

Future lessons will be introduced as needed while building real projects:

  • Interfaces

  • Testing

  • Cryptography packages

  • Context

  • Goroutines (if required)

  • Standard library patterns