Работа с JSON в Go
Полное руководство по работе с JSON в Go: файлы, API и базы данных
Categories:
1. Основы работы с JSON в Go
Структуры для маршалинга/анмаршалинга
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
Roles []string `json:"roles"`
IsActive bool `json:"is_active"`
}
Преобразование структур в JSON
user := User{
ID: 1,
Name: "Alice",
Email: "alice@example.com",
Roles: []string{"admin", "user"},
IsActive: true,
}
jsonData, err := json.Marshal(user)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(jsonData))
// Output: {"id":1,"name":"Alice","email":"alice@example.com","roles":["admin","user"],"is_active":true}
Чтение JSON в структуру
var decodedUser User
err = json.Unmarshal(jsonData, &decodedUser)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", decodedUser)
2. Работа с JSON-файлами
Запись JSON в файл
func writeJSON(filename string, data interface{}) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
encoder := json.NewEncoder(file)
encoder.SetIndent("", " ") // Форматирование с отступами
return encoder.Encode(data)
}
// Использование
err := writeJSON("user.json", user)
Чтение JSON из файла
func readJSON(filename string, target interface{}) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
return json.NewDecoder(file).Decode(target)
}
// Использование
var userFromFile User
err := readJSON("user.json", &userFromFile)
3. Обработка директорий с JSON-файлами
Чтение всех JSON-файлов в директории
func readAllJSONFiles(dirPath string) ([]User, error) {
var users []User
files, err := os.ReadDir(dirPath)
if err != nil {
return nil, err
}
for _, file := range files {
if !strings.HasSuffix(file.Name(), ".json") {
continue
}
var user User
err := readJSON(filepath.Join(dirPath, file.Name()), &user)
if err != nil {
return nil, err
}
users = append(users, user)
}
return users, nil
}
Пример: Сохранение множества файлов
users := []User{
{ID: 1, Name: "Alice"},
{ID: 2, Name: "Bob"},
}
for _, user := range users {
filename := fmt.Sprintf("user_%d.json", user.ID)
err := writeJSON(filename, user)
if err != nil {
log.Printf("Error saving %s: %v", filename, err)
}
}
4. Взаимодействие с API
Отправка JSON через HTTP POST
func sendUserToAPI(url string, user User) (*http.Response, error) {
jsonData, err := json.Marshal(user)
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
if err != nil {
return nil, err
}
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer token123")
client := &http.Client{}
return client.Do(req)
}
// Использование
resp, err := sendUserToAPI("https://api.example.com/users", user)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
Чтение JSON-ответа от API
func getUsersFromAPI(url string) ([]User, error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API returned status: %s", resp.Status)
}
var users []User
err = json.NewDecoder(resp.Body).Decode(&users)
return users, err
}
5. Продвинутые техники
Кастомный парсинг дат в JSON
type CustomTime time.Time
func (ct *CustomTime) UnmarshalJSON(b []byte) error {
s := strings.Trim(string(b), `"`)
t, err := time.Parse("2006-01-02", s)
if err != nil {
return err
}
*ct = CustomTime(t)
return nil
}
type Event struct {
Name string `json:"name"`
Date CustomTime `json:"date"`
}
Обработка динамических JSON-структур
var data map[string]interface{}
err := json.Unmarshal(jsonData, &data)
if err != nil {
log.Fatal(err)
}
if name, ok := data["name"].(string); ok {
fmt.Println("Name:", name)
}
6. Полный пример: CRUD с JSON-файлами
package main
import (
"encoding/json"
"fmt"
"log"
"os"
"path/filepath"
)
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
const storageDir = "data/users"
func init() {
os.MkdirAll(storageDir, 0755)
}
func saveUser(user User) error {
filename := filepath.Join(storageDir, fmt.Sprintf("%d.json", user.ID))
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
encoder := json.NewEncoder(file)
encoder.SetIndent("", " ")
return encoder.Encode(user)
}
func getUser(id int) (User, error) {
var user User
filename := filepath.Join(storageDir, fmt.Sprintf("%d.json", id))
file, err := os.Open(filename)
if err != nil {
return user, err
}
defer file.Close()
err = json.NewDecoder(file).Decode(&user)
return user, err
}
func main() {
user := User{ID: 1, Name: "Alice", Email: "alice@example.com"}
// Create
if err := saveUser(user); err != nil {
log.Fatal(err)
}
// Read
savedUser, err := getUser(1)
if err != nil {
log.Fatal(err)
}
fmt.Printf("User: %+v\n", savedUser)
}
7. Оптимизация работы с большими JSON
Стриминг при записи
func writeLargeJSON(filename string, data []User) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
encoder := json.NewEncoder(file)
for _, item := range data {
if err := encoder.Encode(item); err != nil {
return err
}
}
return nil
}
Построчное чтение больших файлов
func readLargeJSON(filename string) ([]User, error) {
file, err := os.Open(filename)
if err != nil {
return nil, err
}
defer file.Close()
var users []User
decoder := json.NewDecoder(file)
for decoder.More() {
var user User
if err := decoder.Decode(&user); err != nil {
return nil, err
}
users = append(users, user)
}
return users, nil
}
8. Безопасность и валидация
Валидация JSON-схемы
import "github.com/xeipuuv/gojsonschema"
func validateJSON(schemaPath string, jsonData []byte) error {
schemaLoader := gojsonschema.NewReferenceLoader("file://" + schemaPath)
documentLoader := gojsonschema.NewBytesLoader(jsonData)
result, err := gojsonschema.Validate(schemaLoader, documentLoader)
if err != nil {
return err
}
if !result.Valid() {
return fmt.Errorf("validation errors: %v", result.Errors())
}
return nil
}
Защита от переполнения при парсинге
decoder := json.NewDecoder(file)
decoder.DisallowUnknownFields() // Запрет неизвестных полей
Полезные материалы:
- JSON Schema для сложной валидации
- Альтернативные JSON-парсеры: json-iterator
- Бинарные JSON-альтернативы: Protocol Buffers, MessagePack