Cómo convertir Go struct a JSON: de principiante a experto
Trabajar con JSON es el pan de cada día para cualquier desarrollador backend en Go. Prácticamente todos los días tienes que enviar datos al cliente, recibir solicitudes de una API o guardar configuraciones. Y en el 90% de los casos es JSON. Pero, ¿cómo transformar correctamente tu struct nativa en un JSON legible? Parecería que no podría ser más sencillo. Sin embargo, el diablo está en los detalles: etiquetas incorrectas, campos vacíos, errores olvidados — y tu API ya no devuelve lo que debería.
En este artículo analizaremos la conversión de Go struct a JSON desde lo más básico hasta técnicas avanzadas. Aprenderás cómo funcionan las etiquetas, cómo ocultar campos vacíos, cómo serializar estructuras anidadas y cómo no cometer errores. ¡Vamos allá!
Fundamentos: paquete encoding/json
En la biblioteca estándar de Go existe un potente paquete llamado encoding/json. Sus herramientas principales son las funciones json.Marshal (para convertir struct en JSON) y json.Unmarshal (para el proceso inverso).
Veamos un ejemplo básico. Tenemos una estructura de usuario:
package main
import ( "encoding/json" "fmt")
type User struct { Name string Age int Email string}
func main() { user := User{ Name: "Alexei", Age: 30, Email: "alex@example.com", }
jsonData, err := json.Marshal(user) if err != nil { fmt.Println("Error:", err) return }
fmt.Println(string(jsonData)) // Salida: {"Name":"Alexei","Age":30,"Email":"alex@example.com"}}Funciona, pero hay un detalle: las claves en JSON coinciden con los nombres de los campos de la estructura (con mayúscula inicial). Esto no sigue los estándares de JSON (normalmente se usa camelCase o snake_case).
Etiquetas JSON: control sobre los nombres de las claves
Para controlar cómo se verán los campos en JSON, se utilizan las etiquetas de estructura. Son anotaciones especiales que se escriben después del tipo del campo entre comillas invertidas.
type User struct { Name string `json:"name"` Age int `json:"age"` Email string `json:"email"`}
// Ahora la salida será:// {"name":"Alexei","age":30,"email":"alex@example.com"}Las etiquetas resuelven varias tareas:
- Cambiar el nombre del campo — haces las claves bonitas y legibles
- Omitir el campo — con
json:"-"el campo se excluye completamente del JSON - Gestionar campos vacíos — la opción
omitemptyoculta el campo si contiene un valor cero
Ejemplo práctico con omitempty
type User struct { Name string `json:"name"` Age int `json:"age,omitempty"` Email string `json:"email,omitempty"` IsAdmin bool `json:"is_admin,omitempty"`}
func main() { user := User{Name: "María"} jsonData, _ := json.Marshal(user) fmt.Println(string(jsonData)) // Salida: {"name":"María"} // Age, Email e IsAdmin se omiten porque están vacíos}Ten en cuenta: omitempty funciona con valores cero — 0, false, cadena vacía, nil. Esto es muy útil para APIs donde no es necesario arrastrar campos adicionales.
Estructuras anidadas y slices
En proyectos reales, los datos rara vez son planos. A menudo tienes objetos anidados o arrays. Go maneja esto perfectamente — el paquete json procesa recursivamente todos los campos.
type Address struct { City string `json:"city"` Street string `json:"street"` ZipCode string `json:"zip_code"`}
type Company struct { Name string `json:"name"` Address Address `json:"address"` Tags []string `json:"tags"`}
func main() { company := Company{