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
MarshalIndentfor 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.