POST-request com JSON em Go: do iniciante à produção

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Enviando JSON em uma requisição POST em Go: de "como isso funciona" a "feito e esquecido"



Você já ficou preso no Stack Overflow, tentando entender por que sua requisição POST com JSON em Go não é aceita pelo servidor? Familiar: parece que está tudo certo, mas a resposta é 400 Bad Request ou corpo vazio. Acontece que em Go existem várias maneiras de enviar JSON, e escolher a correta não é apenas uma questão de gosto, mas uma questão de estabilidade do seu microsserviço.



Neste artigo, não vamos apenas mostrar código. Vamos analisar três abordagens: desde a ingênua (que funciona, mas é perigosa) até a solução de produção com tratamento adequado de erros e contextos. Se você programa em Go para APIs, bots ou integrações, esta é uma leitura obrigatória.



Por que este tópico é tão popular?

Go é uma linguagem para serviços de rede. Mais cedo ou mais tarde, qualquer desenvolvedor enfrenta a tarefa: "enviar JSON no corpo de uma requisição POST". Parece simples, mas há nuances:

  • É necessário serializar corretamente a estrutura em JSON (marshalling).
  • É importante não esquecer o cabeçalho Content-Type: application/json.
  • É preciso fechar corretamente o corpo da resposta.
  • Deseja-se evitar vazamentos de memória e pânicos.

Vamos analisar cada abordagem com exemplos práticos.



Abordagem 1: "Na gambiarra" — bytes.NewBuffer + json.Marshal

Esta é a maneira mais simples. Pegamos uma estrutura, fazemos o marshalling em bytes, colocamos em um buffer e enviamos. Muitos desenvolvedores Go iniciantes escrevem exatamente assim.



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: "João Silva", Email: "joao@example.com"} // Passo 1: fazer marshalling da estrutura para JSON jsonData, err := json.Marshal(user) if err != nil { fmt.Println("Erro de marshalling:", err) return } // Passo 2: criar requisição POST resp, err := http.Post( "https://api.example.com/users", "application/json", bytes.NewBuffer(jsonData), ) if err != nil { fmt.Println("Erro na requisição:", err) return } defer resp.Body.Close() fmt.Println("Status:", resp.Status)}


Prós e contras desta abordagem

  • Pró: Mínimo de código, claro para iniciantes.
  • Contra: Sem flexibilidade. Você não pode adicionar cabeçalhos personalizados (autenticação, trace-id). Sem controle sobre timeouts. Se o servidor retornar um erro, você não o tratará.
  • Contra: Problema potencial: se json.Marshal retornar um erro, você o capturará, mas no código real muitas vezes esquecem de verificar.

Esta abordagem serve para protótipos e testes. Para produção, não.



Abordagem 2: "A correta" — http.NewRequest + json.NewEncoder

A comunidade Go recomenda usar http.NewRequest e json.NewEncoder. Por quê? Porque oferece controle total sobre a requisição e é mais eficiente em termos de memória.



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 { // Criar buffer e encoder var buf bytes.Buffer enc := json.NewEncoder(&buf) // Codificar diretamente no buffer (sem []byte intermediário) if err := enc.Encode(order); err != nil { return fmt.Errorf("erro na codificação JSON: %w", err) } // Criar requisição req, err := http.NewRequest("POST", "https://api.example.com/orders", &buf) if err != nil { return fmt.Errorf("erro ao criar requisição: %w", err) } // Definir cabeçalhos req.Header.Set("Content-Type", "application/json") req.Hea

Blogs

Book Recommendations