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!