Introdução
Go (Golang) é uma linguagem compilada moderna do Google, ideal para criar serviços de rede de alta carga. O pacote embutido net/http fornece um cliente HTTP poderoso e flexível que permite interagir facilmente com APIs REST, servidores web e outros recursos HTTP. No entanto, apesar da aparente simplicidade, iniciantes frequentemente cometem erros típicos: esquecem de fechar o corpo da resposta, não tratam timeouts ou ignoram erros.
Neste artigo, vamos analisar como usar corretamente o cliente HTTP em Go. Você aprenderá a fazer requisições GET e POST, gerenciar cabeçalhos, configurar timeouts e tratar erros. Todos os exemplos de código estão prontos para uso em seus projetos.
1. Fundamentos: Requisição GET e leitura da resposta
A maneira mais simples de executar uma requisição GET é usar a função http.Get(). No entanto, para código de produção, é recomendado criar sua própria instância de http.Client — isso dá mais controle sobre o comportamento do cliente.
Requisição GET simples
package main
import ( "fmt" "io" "net/http" "os")
func main() { // Cria um cliente (por enquanto com configurações padrão) client := &http.Client{} // Executa a requisição GET resp, err := client.Get("https://api.example.com/data") if err != nil { fmt.Fprintf(os.Stderr, "Erro na requisição: %v", err) os.Exit(1) } // IMPORTANTE: fecha o corpo da resposta defer resp.Body.Close()
// Lê o corpo da resposta body, err := io.ReadAll(resp.Body) if err != nil { fmt.Fprintf(os.Stderr, "Erro ao ler o corpo: %v", err) os.Exit(1) }
fmt.Printf("Status: %s", resp.Status) fmt.Printf("Corpo: %s", body)}Pontos-chave:
defer resp.Body.Close()— feche sempre o corpo da resposta, caso contrário ocorrerá vazamento de recursos (a conexão não retornará ao pool).- Sempre verifique
err— a rede é instável e a requisição pode falhar. - Verifique o status HTTP da resposta (
resp.StatusCode) para distinguir sucesso (2xx) de erros do servidor (4xx, 5xx).
2. Requisição POST com corpo e cabeçalhos
Para enviar dados ao servidor (por exemplo, JSON), usa-se http.Post() ou o método mais flexível http.NewRequest() seguido da chamada client.Do(). A segunda forma é preferível, pois permite definir cabeçalhos e outros parâmetros.
POST com dados JSON
package main
import ( "bytes" "encoding/json" "fmt" "net/http" "os")
type User struct { Name string `json:"name"` Email string `json:"email"`}
func main() { client := &http.Client{}
// Prepara os dados user := User{Name: "Ivan Petrov", Email: "ivan@example.com"} jsonData, err := json.Marshal(user) if err != nil { fmt.Fprintf(os.Stderr, "Erro na serialização JSON: %v", err) os.Exit(1) }
// Cria a requisição req, err := http.NewRequest("POST", "https://api.example.com/users", bytes.NewBuffer(jsonData)) if err != nil { fmt.Fprintf(os.Stderr, "Erro ao criar requisição: %v", err) os.Exit(1) }
// Define os cabeçalhos req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", "Bearer YOUR_TOKEN_HERE")
// Envia a requisição resp, err := client.Do(req) if err != nil { fmt.Fprintf(os.Stderr, "Erro na requisição: %v", err) os.Exit(1) } defer resp.Body.Close()
// Verifica o status if resp.StatusCode != http.StatusCreated { fmt.Fprintf(os.Stderr, "Servidor retornou erro: %s", resp.Status) os.Exit(1) }
fmt.Println("Usuário criado com sucesso!")}Import