Introdução: por que Go é a escolha ideal para APIs REST
Go (ou Golang) é uma linguagem de programação compilada do Google que combina o desempenho do C++ com a simplicidade do Python. Se você deseja criar uma API REST rápida, confiável e de fácil manutenção, Go é uma das melhores opções. Neste artigo, em 30 minutos, escreveremos uma API REST completa em Go, capaz de criar, ler, atualizar e excluir registros (CRUD). Nada de frameworks complexos — apenas a biblioteca padrão net/http e um pouco de código.
Ao final do artigo, você terá um servidor HTTP pronto que responde a requisições no formato JSON e funciona sem dependências externas. Vamos lá!
Passo 1: Configuração do projeto e estrutura
Para começar, certifique-se de ter o Go instalado (versão 1.16+). Crie um novo diretório para o projeto e inicialize o módulo:
mkdir go-rest-apicd go-rest-apigo mod init go-rest-apiA estrutura do projeto será simples — um único arquivo main.go. Colocaremos todo o código nele para não complicar o exemplo. Em projetos reais, você certamente dividirá o código em pacotes, mas para aprendizado, esta é a opção ideal.
Passo 2: Definindo a estrutura de dados e o armazenamento global
Nossa API gerenciará uma lista de livros. Vamos criar a estrutura Book e um slice simples para armazenar os dados em memória (em vez de um banco de dados).
package main
import ( "encoding/json" "log" "net/http" "strconv" "strings")
type Book struct { ID int `json:"id"` Title string `json:"title"` Author string `json:"author"` Year int `json:"year"`}
var books []Bookvar nextID int = 1Aqui, books é nossa "camada de dados" temporária, e nextID é um contador para atribuir automaticamente IDs a novos livros.
Passo 3: Implementando os manipuladores de requisições HTTP (CRUD)
Agora a parte mais interessante — vamos escrever funções manipuladoras para cada método HTTP. Usaremos o roteador padrão http.NewServeMux.
3.1. Obtendo todos os livros (GET /books)
func getBooks(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(books)}3.2. Criando um novo livro (POST /books)
func createBook(w http.ResponseWriter, r *http.Request) { var newBook Book if err := json.NewDecoder(r.Body).Decode(&newBook); err != nil { http.Error(w, "Invalid JSON", http.StatusBadRequest) return } newBook.ID = nextID nextID++ books = append(books, newBook) w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(newBook)}3.3. Obtendo um livro por ID (GET /books/{id})
No ServeMux padrão não há suporte para rotas dinâmicas, então extrairemos o ID da URL manualmente.
func getBook(w http.ResponseWriter, r *http.Request) { idStr := strings.TrimPrefix(r.URL.Path, "/books/") id, err := strconv.Atoi(idStr) if err != nil { http.Error(w, "Invalid ID", http.StatusBadRequest) return } for _, book := range books { if book.ID == id { w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(book) return } } http.Error(w, "Book not found", http.StatusNotFound)}3.4. Atualizando um livro (PUT /books/{id})
func updateBook(w http.ResponseWriter, r *http.Request) { idStr := strings.TrimPrefix(r.URL.Path, "/books/") id, err := strconv.Atoi(idStr) if err != nil { http.Error(w, "Invalid ID", http.StatusBadRequest) return } var updatedBook Book if err := json.NewDecoder(r.Body).Decode(&updatedBook); err != nil { h