Lectura y escritura de JSON en Go (encoding/json)

En Go no hace falta instalar nada extra: el paquete encoding/json de la biblioteca estándar permite serializar (Go → JSON) y deserializar (JSON → Go).

📌 Ejemplo completo: Serializar (Go → JSON)

package main

import (
    "encoding/json"
    "fmt"
)

type Producto struct {
    Codigo      int      `json:"codigo"`
    Descripcion string   `json:"descripcion"`
    Precio      float64  `json:"precio"`
    Disponible  bool     `json:"disponible"`
    Tags        []string `json:"tags"`
}

func main() {
    prod := Producto{
        Codigo:      101,
        Descripcion: "Teclado mecánico",
        Precio:      1200.50,
        Disponible:  true,
        Tags:        []string{"periférico", "oferta"},
    }

    // Convertir struct a JSON
    jsonData, err := json.Marshal(prod)
    if err != nil {
        panic(err)
    }

    fmt.Println(string(jsonData))
    // {"codigo":101,"descripcion":"Teclado mecánico","precio":1200.5,"disponible":true,"tags":["periférico","oferta"]}
}

👉 json.Marshal() convierte un struct Go en []byte con el JSON.

📌 Ejemplo con formato legible (MarshalIndent)

jsonPretty, err := json.MarshalIndent(prod, "", "  ")
if err != nil {
    panic(err)
}
fmt.Println(string(jsonPretty))
// Salida con sangría

📌 Ejemplo completo: Deserializar (JSON → Go)

package main

import (
    "encoding/json"
    "fmt"
)

type Producto struct {
    Codigo      int      `json:"codigo"`
    Descripcion string   `json:"descripcion"`
    Precio      float64  `json:"precio"`
    Disponible  bool     `json:"disponible"`
    Tags        []string `json:"tags"`
}

func main() {
    jsonString := `{
        "codigo": 102,
        "descripcion": "Mouse inalámbrico",
        "precio": 850.75,
        "disponible": false,
        "tags": ["periférico"]
    }`

    var prod Producto

    // Convertir JSON → struct
    if err := json.Unmarshal([]byte(jsonString), &prod); err != nil {
        panic(err)
    }

    fmt.Println(prod.Descripcion) // Mouse inalámbrico
    fmt.Println(prod.Precio)      // 850.75
}

👉 json.Unmarshal() convierte JSON ([]byte) en un struct Go.

📌 Ejemplo: Listas de objetos JSON

package main

import (
    "encoding/json"
    "fmt"
)

type Producto struct {
    Codigo      int     `json:"codigo"`
    Descripcion string  `json:"descripcion"`
    Precio      float64 `json:"precio"`
}

func main() {
    jsonString := `[
        {"codigo": 201, "descripcion": "Monitor 24 pulgadas", "precio": 1500.00},
        {"codigo": 202, "descripcion": "Notebook", "precio": 2500.50}
    ]`

    var productos []Producto
    if err := json.Unmarshal([]byte(jsonString), &productos); err != nil {
        panic(err)
    }

    for _, p := range productos {
        fmt.Printf("%d - %s ($%.2f)\n", p.Codigo, p.Descripcion, p.Precio)
    }
}

📌 Ejemplo: Leer y escribir JSON en archivo

package main

import (
    "encoding/json"
    "fmt"
    "os"
)

type Usuario struct {
    Nombre string `json:"nombre"`
    Edad   int    `json:"edad"`
    Activo bool   `json:"activo"`
}

func main() {
    usuario := Usuario{"María", 29, true}

    // Guardar en archivo
    file, err := os.Create("usuario.json")
    if err != nil {
        panic(err)
    }
    defer file.Close()

    encoder := json.NewEncoder(file)
    encoder.SetIndent("", "  ") // salida legible
    if err := encoder.Encode(usuario); err != nil {
        panic(err)
    }

    // Leer desde archivo
    file2, err := os.Open("usuario.json")
    if err != nil {
        panic(err)
    }
    defer file2.Close()

    var usuarioLeido Usuario
    decoder := json.NewDecoder(file2)
    if err := decoder.Decode(&usuarioLeido); err != nil {
        panic(err)
    }

    fmt.Println("Usuario leído:", usuarioLeido.Nombre, usuarioLeido.Edad)
}

📌 Ejemplo: JSON dinámico con map[string]interface{}

Cuando no conocemos la estructura exacta del JSON, podemos usar un mapa genérico:

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    jsonString := `{"codigo": 301, "extra": {"color": "negro", "stock": 20}}`

    var data map[string]interface{}
    if err := json.Unmarshal([]byte(jsonString), &data); err != nil {
        panic(err)
    }

    fmt.Println(data["codigo"]) // 301
    extra := data["extra"].(map[string]interface{})
    fmt.Println(extra["color"]) // negro
}

📊 Resumen

  • json.Marshal() — Go struct → JSON ([]byte).
  • json.Unmarshal() — JSON ([]byte) → Go struct.
  • MarshalIndent / Encoder.SetIndent — salida legible.
  • Soporta structs, slices y maps.
  • Usar etiquetas json:"campo" para mapear nombres de propiedades.
  • Para JSON desconocido — usar map[string]interface{}.