Como Criar uma API REST com Golang e Gin - Parte 2: Estruturando os Handlers

Na Parte 1 criamos nosso primeiro endpoint. Agora vamos estruturar uma API CRUD completa para gerenciar uma biblioteca de livros.

Modelo de Dados

Primeiro, defina a struct Book em main.go (ou em um arquivo models/book.go):

type Book struct {
    ID     string  `json:"id"`
    Title  string  `json:"title"`
    Author string  `json:"author"`
    Price  float64 `json:"price"`
}

Banco de Dados em Memória

Para simplificar, usaremos um slice em memória:

var books = []Book{
    {ID: "1", Title: "Clean Code", Author: "Robert Martin", Price: 89.90},
    {ID: "2", Title: "The Go Programming Language", Author: "Alan Donovan", Price: 120.00},
}

Handlers (Controllers)

Crie handlers separados para organizar o código:

// GET /books - Lista todos os livros
func getBooks(c *gin.Context) {
    c.JSON(200, books)
}

// GET /books/:id - Busca um livro pelo ID
func getBook(c *gin.Context) {
    id := c.Param("id")
    for _, book := range books {
        if book.ID == id {
            c.JSON(200, book)
            return
        }
    }
    c.JSON(404, gin.H{"error": "Livro não encontrado"})
}

// POST /books - Cria um novo livro
func createBook(c *gin.Context) {
    var newBook Book
    if err := c.ShouldBindJSON(&newBook); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }
    books = append(books, newBook)
    c.JSON(201, newBook)
}

// PUT /books/:id - Atualiza um livro
func updateBook(c *gin.Context) {
    id := c.Param("id")
    var updatedBook Book
    if err := c.ShouldBindJSON(&updatedBook); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }
    for i, book := range books {
        if book.ID == id {
            books[i] = updatedBook
            c.JSON(200, updatedBook)
            return
        }
    }
    c.JSON(404, gin.H{"error": "Livro não encontrado"})
}

// DELETE /books/:id - Remove um livro
func deleteBook(c *gin.Context) {
    id := c.Param("id")
    for i, book := range books {
        if book.ID == id {
            books = append(books[:i], books[i+1:]...)
            c.Status(204)
            return
        }
    }
    c.JSON(404, gin.H{"error": "Livro não encontrado"})
}

Configurando as Rotas

func main() {
    r := gin.Default()

    // Grupo de rotas para /books
    books := r.Group("/books")
    {
        books.GET("", getBooks)
        books.GET("/:id", getBook)
        books.POST("", createBook)
        books.PUT("/:id", updateBook)
        books.DELETE("/:id", deleteBook)
    }

    r.Run(":8080")
}

Testando a API

Use curl ou Postman:

# Listar livros
curl http://localhost:8080/books

# Buscar livro
curl http://localhost:8080/books/1

# Criar livro
curl -X POST http://localhost:8080/books \
  -H "Content-Type: application/json" \
  -d '{"id":"3","title":"Domain-Driven Design","author":"Eric Evans","price":150.00}'

# Atualizar livro
curl -X PUT http://localhost:8080/books/1 \
  -H "Content-Type: application/json" \
  -d '{"id":"1","title":"Clean Code (Atualizado)","author":"Robert Martin","price":99.90}'

# Deletar livro
curl -X DELETE http://localhost:8080/books/3

Próximos Passos

Na Parte 3, vamos:

  • Adicionar validação de dados (binding + validator)
  • Middleware para logging e autenticação
  • Tratamento de erros estruturado

👉 Parte 3: Validação e Middleware


Gostou deste tutorial? Compartilhe no Twitter e deixe seu feedback no Telegram!