Введение в работу с JSON в Go
JSON (JavaScript Object Notation) — это один из самых популярных форматов обмена данными в современных веб-приложениях, микросервисах и API. Язык Go (Golang) предлагает встроенную мощную поддержку для работы с JSON через пакет encoding/json. Этот пакет позволяет легко преобразовывать данные между Go-структурами и JSON-строками, а также наоборот.
В этой статье мы подробно разберём, как выполнять парсинг (десериализацию) и сериализацию JSON в Go. Вы узнаете, как работать с простыми и вложенными структурами, обрабатывать ошибки и настраивать имена полей. Материал будет полезен как начинающим, так и опытным разработчикам, которые хотят систематизировать знания.
Основы сериализации (Marshal) в Go
Преобразование Go-структуры в JSON
Сериализация — это процесс преобразования Go-объекта (например, структуры или слайса) в JSON-строку. Для этого используется функция json.Marshal(). Рассмотрим простейший пример:
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Name string
Age int
Email string
}
func main() {
user := User{
Name: "Иван Петров",
Age: 30,
Email: "ivan@example.com",
}
jsonData, err := json.Marshal(user)
if err != nil {
fmt.Println("Ошибка сериализации:", err)
return
}
fmt.Println(string(jsonData))
}
Вывод программы:
{"Name":"Иван Петров","Age":30,"Email":"ivan@example.com"}
Обратите внимание: имена полей в JSON совпадают с именами полей структуры. Но часто требуется изменить их, например, сделать в стиле camelCase. Для этого используются теги структур.
Использование тегов для настройки JSON
Теги структур позволяют задать, как именно поле будет сериализоваться. Добавим теги к нашему примеру:
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Email string `json:"email,omitempty"`
}
Теперь вывод будет таким:
{"name":"Иван Петров","age":30,"email":"ivan@example.com"}
Ключевые опции тегов:
json:"field_name"— задаёт имя поля в JSON.omitempty— исключает поле из JSON, если оно имеет нулевое значение (пустая строка, 0, false, nil).-— полностью игнорирует поле при сериализации/десериализации.
Сериализация слайсов и мап
Пакет encoding/json отлично работает не только со структурами, но и со слайсами, мапами и простыми типами:
// Слайс структур
users := []User{
{Name: "Анна", Age: 25},
{Name: "Борис", Age: 35},
}
jsonUsers, _ := json.Marshal(users)
fmt.Println(string(jsonUsers))
// Вывод: [{"name":"Анна","age":25},{"name":"Борис","age":35}]
// Мапа
data := map[string]interface{}{
"status": "ok",
"count": 42,
}
jsonMap, _ := json.Marshal(data)
fmt.Println(string(jsonMap))
// Вывод: {"count":42,"status":"ok"}
Парсинг JSON (Unmarshal) в Go
Базовый парсинг в структуру
Десериализация (парсинг) — это обратный процесс: преобразование JSON-строки в Go-объект. Используется функция json.Unmarshal(). Важно: целевая структура должна быть экспортирована (поля с большой буквы) или иметь соответствующие теги.
jsonString := `{"name":"Мария","age":28,"email":"maria@example.com"}`
var user User
err := json.Unmarshal([]byte(jsonString), &user)
if err != nil {
fmt.Println("Ошибка парсинга:", err)
return
}
fmt.Printf("Имя: %s, Возраст: %d\n", user.Name, user.Age)
// Вывод: Имя: Мария, Возраст: 28
Парсинг вложенных структур
JSON часто содержит вложенные объекты. Go позволяет моделировать их с помощью вложенных структур:
type Address struct {
City string `json:"city"`
Street string `json:"street"`
}
type Person struct {
Name string `json:"name"`
Age int `json:"age"`
Address Address `json:"address"`
}
func main() {
jsonData := `{
"name": "Алексей",
"age": 40,
"address": {
"city": "Москва",
"street": "Тверская"
}
}`
var person Person
json.Unmarshal([]byte(jsonData), &person)
fmt.Printf("%s живёт в городе %s\n", person.Name, person.Address.City)
// Вывод: Алексей живёт в городе Москва
}
Парсинг в map[string]interface{}
Если структура заранее неизвестна, можно использовать map[string]interface{}. Это гибкий, но менее безопасный подход, так как требует приведения типов:
jsonString := `{"name":"Ольга","age":32,"skills":["Go","Python","SQL"]}`
var result map[string]interface{}
json.Unmarshal([]byte(jsonString), &result)
name := result["name"].(string)
age := result["age"].(float64) // числа в JSON всегда float64
skills := result["skills"].([]interface{})
fmt.Printf("Имя: %s, Возраст: %.0f\n", name, age)
fmt.Println("Навыки:")
for _, skill := range skills {
fmt.Println("-", skill)
}
Продвинутые приёмы работы с JSON
Форматированный вывод (Pretty Print)
Для отладки часто требуется вывести JSON с отступами. Используйте json.MarshalIndent():
user := User{Name: "Дмитрий", Age: 45}
jsonPretty, _ := json.MarshalIndent(user, "", " ")
fmt.Println(string(jsonPretty))
Вывод:
{
"name": "Дмитрий",
"age": 45
}
Обработка ошибок и валидация
Всегда проверяйте ошибки после Marshal и Unmarshal. Типичные