POST-request con JSON en Go: de principiante a producción

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Enviamos JSON en una solicitud POST en Go: de "cómo funciona esto" a "hecho y olvidado"



¿Alguna vez te has quedado atascado en Stack Overflow tratando de entender por qué tu solicitud POST con JSON en Go no es aceptada por el servidor? Te suena: parece que todo está correcto, pero la respuesta es 400 Bad Request o un cuerpo vacío. Resulta que en Go hay varias formas de enviar JSON, y elegir la correcta no es solo una cuestión de gusto, sino de la estabilidad de tu microservicio.



En este artículo no solo mostraremos código. Analizaremos tres enfoques: desde el ingenuo (que funciona pero es peligroso) hasta una solución de producción con manejo correcto de errores y contextos. Si escribes en Go para API, bots o integraciones, esta es una lectura obligatoria.



¿Por qué este tema es tan popular?

Go es un lenguaje para servicios de red. Tarde o temprano, cualquier desarrollador se enfrenta a la tarea: "enviar JSON en el cuerpo de una solicitud POST". Parece sencillo, pero hay matices:

  • Es necesario serializar correctamente la estructura a JSON (marshaling).
  • Es importante no olvidar el encabezado Content-Type: application/json.
  • Es necesario cerrar correctamente el cuerpo de la respuesta.
  • Se desea evitar fugas de memoria y pánicos.

Analicemos cada enfoque con ejemplos prácticos.



Enfoque 1: "Sobre la marcha" — bytes.NewBuffer + json.Marshal

Esta es la forma más simple. Tomamos una estructura, la convertimos a bytes, la colocamos en un buffer y la enviamos. Muchos desarrolladores principiantes de Go escriben exactamente así.



package main

import ( "bytes" "encoding/json" "fmt" "net/http")

type User struct { Name string `json:"name"` Email string `json:"email"`}

func main() { user := User{Name: "Iván Petrov", Email: "ivan@example.com"} // Paso 1: convertimos la estructura a JSON jsonData, err := json.Marshal(user) if err != nil { fmt.Println("Error de marshaling:", err) return } // Paso 2: creamos la solicitud POST resp, err := http.Post( "https://api.example.com/users", "application/json", bytes.NewBuffer(jsonData), ) if err != nil { fmt.Println("Error en la solicitud:", err) return } defer resp.Body.Close() fmt.Println("Estado:", resp.Status)}


Ventajas y desventajas de este enfoque

  • Ventaja: Mínimo código, comprensible para un principiante.
  • Desventaja: Sin flexibilidad. No puedes agregar encabezados personalizados (autorización, trace-id). No hay control sobre los tiempos de espera. Si el servidor devuelve un error, no lo manejas.
  • Desventaja: Problema potencial: si json.Marshal devuelve un error, lo capturas, pero en el código real a menudo se olvida verificarlo.

Este método sirve para prototipos y pruebas. Para producción, no.



Enfoque 2: "El correcto" — http.NewRequest + json.NewEncoder

La comunidad de Go recomienda usar http.NewRequest y json.NewEncoder. ¿Por qué? Porque da control total sobre la solicitud y es más eficiente en memoria.



package main

import ( "bytes" "encoding/json" "fmt" "net/http" "time")

type Order struct { ID int `json:"id"` Amount float64 `json:"amount"` Items []string `json:"items"`}

func sendOrder(order Order) error { // Creamos un buffer y un codificador var buf bytes.Buffer enc := json.NewEncoder(&buf) // Codificamos directamente en el buffer (sin []byte intermedio) if err := enc.Encode(order); err != nil { return fmt.Errorf("error de codificación JSON: %w", err) } // Creamos la solicitud req, err := http.NewRequest("POST", "https://api.example.com/orders", &buf) if err != nil { return fmt.Errorf("error al crear la solicitud: %w", err) } // Establecemos los encabezados req.Header.Set("Content-Type", "application/json") req.Hea

Blogs

Book Recommendations