16 Mapeando Propiedades JSON en Go

Published Jun 24, 2024

GoProgrammingjson

🧠 Introducción

En un mundo ideal, todos usaríamos el mismo estándar para nombrar campos: camelCase, snake_case, o al menos sin espacios. Pero no vivimos en ese mundo 😅

En la práctica, cuando consumes un API externo o trabajas con archivos JSON variados, te puedes encontrar cosas como:

{ "updated at": "06/06/2024", "ID": "1", "nombre": "uva" }

Y si no lo manejas bien, tu aplicación puede romperse.

1. 🎯 ¿Cómo se hace el mapeo de campos en Go?

Sabemos que para mapear un JSON a un struct usamos json.Unmarshal. Pero si los nombres de los campos no coinciden exactamente, no se asignarán.

Ejemplo:

type Product struct {
	Id        string
	Name      string
	UpdatedAt string
}

Y el JSON:

{
  "id": "1",
  "name": "grapes",
  "updated at": "06/06/2024"
}

Accederás correctamente a id y name, pero UpdatedAt estará vacío. ¿Por qué? Porque "updated at" ≠ "UpdatedAt".

2. 🛠️ Solución: Tags en campos del struct

Para mapear nombres no estándar del JSON a campos Go, usamos etiquetas:

type Product struct {
	Id        string `json:"id"`
	Name      string `json:"name"`
	UpdatedAt string `json:"updated at"`
}

Ahora el unmarshalling asigna correctamente incluso campos con espacios, mayúsculas, u otros formatos.

3. 🌪️ ¿Y si el JSON es muy dinámico o no sabemos su estructura?

Si no queremos (o no podemos) definir un struct, usamos:

map[string]interface{}

Eso nos da la flexibilidad de acceder a cualquier campo del JSON como si fuera un map.

Ejemplo:

jsonString := `{
   "name":"ElprogramadorGT",
   "eye_color":"brown",
   "gender":"male",
   "movies":{
      "The Matrix":1999,
      "Interstellar":2014,
      "Parasite":2019
   }
}`

var result map[string]interface{}
json.Unmarshal([]byte(jsonString), &result)

fmt.Println(result["movies"])

result["movies"] es una interface{}, así que no puedes acceder directamente a "Parasite" sin un type assertion.

4. 🧠 Type Assertion: accediendo a datos anidados

Go no hace castings automáticos. Si necesitas acceder a "Parasite":

movies := result["movies"].(map[string]interface{})
fmt.Println(movies["Parasite"]) // 2019

Así le estás diciendo: “Confío en que esto es un map dentro del map”.

⚠️ Si el tipo no coincide, Go lanza panic. Puedes hacer un type assertion seguro con:

if movies, ok := result["movies"].(map[string]interface{}); ok {
	fmt.Println(movies["Parasite"])
}

✅ Conclusión

  • JSON no siempre viene con campos bien nombrados o estandarizados.
  • En Go, usamos tags en structs (json:"campo_json") para mapear correctamente los datos.
  • Para datos dinámicos o muy variables, puedes usar map[string]interface{}.
  • Go requiere type assertions para acceder a campos anidados dentro de interface{}.

🛠️ Práctica recomendada

  1. Crea un struct Person con campos como "first name" y "birth year", y usa tags para mapearlos.
  2. Carga un JSON dinámico con map[string]interface{} que incluya al menos un objeto anidado.
  3. Accede a los campos anidados usando type assertion.
  4. Implementa una verificación segura (if ok) para evitar errores si la estructura cambia.

🚀 Siguientes pasos

  • 🔁 Aprende a codificar structs a JSON usando json.Marshal (inverso a Unmarshal).
  • 🧱 Combina structs + maps para escenarios mixtos.
  • 🌐 Integra JSON decoding en una API real con net/http.