Go Lesson 30 – Working with JSON | Dataplexa

Working with JSON in Go

JSON (JavaScript Object Notation) is the most commonly used data format for communication between applications. In Go, JSON is heavily used in APIs, configuration files, microservices, and data exchange systems.

In this lesson, you will learn how to encode Go data into JSON and decode JSON back into Go structures using Go’s standard library.


Why JSON Is Important

JSON is lightweight, human-readable, and language-independent.

  • REST APIs use JSON for request and response payloads
  • Configuration files are often written in JSON
  • Microservices exchange JSON data
  • Frontend and backend systems communicate using JSON

Importing Required Package

Go provides JSON support through the encoding/json package.

import (
    "encoding/json"
    "fmt"
)

Creating a Struct for JSON

JSON in Go is usually mapped to structs.

type User struct {
    ID    int    `json:"id"`
    Name  string `json:"name"`
    Email string `json:"email"`
}

The struct tags tell Go how to map struct fields to JSON keys.


Encoding Struct to JSON

To convert a Go struct into JSON, use json.Marshal().

user := User{
    ID:    101,
    Name:  "Alice",
    Email: "alice@example.com",
}

jsonData, err := json.Marshal(user)
if err != nil {
    fmt.Println("Error:", err)
    return
}

fmt.Println(string(jsonData))

Output:

{"id":101,"name":"Alice","email":"alice@example.com"}

Pretty Printing JSON

For better readability, use json.MarshalIndent().

jsonData, _ := json.MarshalIndent(user, "", "  ")
fmt.Println(string(jsonData))

Decoding JSON into Struct

To convert JSON back into a Go struct, use json.Unmarshal().

jsonInput := `{"id":202,"name":"Bob","email":"bob@example.com"}`

var newUser User
err := json.Unmarshal([]byte(jsonInput), &newUser)
if err != nil {
    fmt.Println("Error:", err)
    return
}

fmt.Println(newUser)

Working with JSON Arrays

JSON often contains arrays of objects.

jsonArray := `[
  {"id":1,"name":"John","email":"john@mail.com"},
  {"id":2,"name":"Sara","email":"sara@mail.com"}
]`

var users []User
json.Unmarshal([]byte(jsonArray), &users)

for _, u := range users {
    fmt.Println(u.Name, u.Email)
}

Using Maps for Dynamic JSON

When JSON structure is unknown, maps can be used.

data := `{"product":"Laptop","price":1200,"stock":25}`

var result map[string]interface{}
json.Unmarshal([]byte(data), &result)

fmt.Println(result["product"])
fmt.Println(result["price"])

Real-World Example: API Response

Typical API response structure.

type APIResponse struct {
    Status  string `json:"status"`
    Message string `json:"message"`
    Data    User   `json:"data"`
}

Encoding response:

response := APIResponse{
    Status:  "success",
    Message: "User fetched successfully",
    Data:    user,
}

jsonResponse, _ := json.MarshalIndent(response, "", "  ")
fmt.Println(string(jsonResponse))

Handling Missing or Optional Fields

If a JSON field is missing, Go assigns zero values automatically.

You can use pointers to detect missing values.

type Profile struct {
    Age *int `json:"age"`
}

Common JSON Errors

  • Incorrect struct tags
  • Type mismatches
  • Invalid JSON formatting
  • Using unexported struct fields

Best Practices

  • Always validate JSON input
  • Use structs for known schemas
  • Use maps for flexible schemas
  • Prefer MarshalIndent for debugging

Practice Exercises

Exercise 1

Create a struct for a product and encode it into JSON.

Exercise 2

Decode a JSON array into a slice of structs.

Exercise 3

Handle optional JSON fields safely.


What’s Next?

In the next lesson, you will learn about Introduction to Concurrency in Go and how Go handles parallel execution efficiently.