Como Criar uma API REST com Golang e Gin - Parte 4: Banco de Dados com GORM

Na parte final da série, vamos conectar nossa API ao PostgreSQL usando GORM (Object Relational Mapping para Go).

Instalando o GORM e Driver PostgreSQL

go get -u gorm.io/gorm
go get -u gorm.io/driver/postgres

Configurando a Conexão

Crie um arquivo db/db.go:

package db

import (
    "fmt"
    "log"
    "gorm.io/driver/postgres"
    "gorm.io/gorm"
)

var DB *gorm.DB

func Connect() {
    dsn := "host=localhost user=postgres password=suasenha dbname=booksdb port=5432 sslmode=disable"
    
    var err error
    DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})
    
    if err != nil {
        log.Fatal("Falha ao conectar ao banco:", err)
    }
    
    fmt.Println("Conectado ao PostgreSQL!")
}

Modelo GORM

Atualize Book para usar tags GORM:

type Book struct {
    ID     uint    `json:"id" gorm:"primaryKey"`
    Title  string  `json:"title" binding:"required,min=3,max=100" gorm:"type:varchar(100);not null"`
    Author string  `json:"author" binding:"required" gorm:"type:varchar(100);not null"`
    Price  float64 `json:"price" binding:"required,gt=0" gorm:"type:decimal(10,2);not null"`
}

Migrations Automáticas

No main.go:

package main

import (
    "github.com/gin-gonic/gin"
    "github.com/seuusuario/golang-api-gin/db"
    "github.com/seuusuario/golang-api-gin/models"
)

func main() {
    // Conecta ao banco
    db.Connect()
    
    // Executa migrations (cria tabelas se não existirem)
    db.DB.AutoMigrate(&models.Book{})
    
    r := gin.Default()
    
    // Rotas (iguais às partes anteriores, mas agora usam o banco)
    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")
}

Handlers com GORM

func getBooks(c *gin.Context) {
    var books []models.Book
    db.DB.Find(&books)
    c.JSON(200, books)
}

func getBook(c *gin.Context) {
    id := c.Param("id")
    var book models.Book
    result := db.DB.First(&book, id)
    
    if result.Error != nil {
        c.JSON(404, gin.H{"error": "Livro não encontrado"})
        return
    }
    
    c.JSON(200, book)
}

func createBook(c *gin.Context) {
    var newBook models.Book
    if err := c.ShouldBindJSON(&newBook); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }
    
    db.DB.Create(&newBook)
    c.JSON(201, newBook)
}

func updateBook(c *gin.Context) {
    id := c.Param("id")
    var updatedBook models.Book
    
    if err := c.ShouldBindJSON(&updatedBook); err != nil {
        c.JSON(400, gin.H{"error": err.Error()})
        return
    }
    
    var book models.Book
    db.DB.First(&book, id)
    
    db.DB.Model(&book).Updates(updatedBook)
    c.JSON(200, book)
}

func deleteBook(c *gin.Context) {
    id := c.Param("id")
    db.DB.Delete(&models.Book{}, id)
    c.Status(204)
}

Dockerizando a Aplicação

Crie um Dockerfile:

FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o api main.go

FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root
COPY --from=builder /app/api .
EXPOSE 8080
CMD ["./api"]

Crie docker-compose.yml:

version: '3.8'
services:
  db:
    image: postgres:15
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: suasenha
      POSTGRES_DB: booksdb
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

  api:
    build: .
    ports:
      - "8080:8080"
    environment:
      DB_HOST: db
      DB_USER: postgres
      DB_PASSWORD: suasenha
      DB_NAME: booksdb
      DB_PORT: 5432
    depends_on:
      - db

volumes:
  postgres_data:

Executando com Docker

docker-compose up --build

Conclusão da Série

Parabéns! Você criou uma API REST completa com: ✅ Framework Gin para rotas
✅ Validação de dados
✅ Middleware de logging e auth
✅ Banco PostgreSQL com GORM
✅ Docker para deploy

Próximos Passos (Além da Série)

  • Adicionar testes automatizados (testing package)
  • Implementar JWT authentication real
  • Configurar CI/CD com GitHub Actions
  • Adicionar logs estruturados (zap logger)
  • Documentação com Swagger (swaggo)

Série completa! Compartilhe no Twitter e deixe seu feedback no Telegram!