Working with JSON in Go: Parsing and Serialization in Practice
JSON (JavaScript Object Notation) is one of the most popular data exchange formats in web development. In the Go language (Golang), working with JSON is implemented through the standard package encoding/json, which provides powerful and convenient tools for serialization (converting data structures to JSON) and deserialization (parsing JSON into Go structures). In this article, we will thoroughly examine how to work with JSON in Go using practical examples.
Basics: Serializing Structures to JSON
The most common way to work with JSON in Go is using structures with tags. Tags allow you to specify JSON field names that may differ from the field names in Go. Let's look at a basic serialization example:
package main
import ( "encoding/json" "fmt")
type User struct { ID int `json:"id"` Name string `json:"name"` Email string `json:"email"` IsActive bool `json:"is_active"`}
func main() { user := User{ ID: 1, Name: "Ivan Petrov", Email: "ivan@example.com", IsActive: true, }
jsonData, err := json.Marshal(user) if err != nil { fmt.Println("Serialization error:", err) return }
fmt.Println(string(jsonData)) // Output: {"id":1,"name":"Ivan Petrov","email":"ivan@example.com","is_active":true}}Note: we use tags json:"field_name" to control the key names in JSON. This is especially convenient when you need to follow certain naming conventions (e.g., snake_case in JSON and CamelCase in Go).
Parsing JSON into Go Structures
Deserialization (parsing) of JSON data into structures is done using the json.Unmarshal function. It is important that the structure matches the structure of the JSON object. Let's continue with our example:
func main() { jsonString := `{"id":2,"name":"Maria Sidorova","email":"maria@example.com","is_active":false}`
var user User err := json.Unmarshal([]byte(jsonString), &user) if err != nil { fmt.Println("Parsing error:", err) return }
fmt.Printf("ID: %d, Name: %s, Email: %s, Active: %t", user.ID, user.Name, user.Email, user.IsActive) // Output: ID: 2, Name: Maria Sidorova, Email: maria@example.com, Active: false}Important: A pointer to the structure (&user) is always passed to the json.Unmarshal function, otherwise changes will not be saved.
Working with Nested Structures and Arrays
Real JSON data often contains nested objects and arrays. Go allows you to elegantly handle such cases using nested structures:
type Address struct { City string `json:"city"` Street string `json:"street"` ZipCode string `json:"zip_code"`}
type Employee struct { ID int `json:"id"` Name string `json:"name"` Skills []string `json:"skills"` Address Address `json:"address"`}
func main() { jsonData := `{ "id": 101, "name": "Alexey Ivanov", "skills": ["Go", "Python", "Docker"], "address": { "city": "Moscow", "street": "Tverskaya, 10", "zip_code": "101000" } }`
var emp Employee err := json.Unmarshal([]byte(jsonData), &emp) if err != nil { fmt.Println("Error:", err) return }
fmt.Printf("Employee: %s, City: %s, Skills: %v", emp.Name, emp.Address.City, emp.Skills) // Output: Employee: Alexey Ivanov, City: Moscow, Skills: [Go Python Docker]}For arrays in Go, slices ([]string) are used, and for nested objects, separate structures are used. When parsing a JSON array of objects, you can