💻 Exemplos: Capítulo 03: Data Binding e Validação de Structs com Validator
Especialização em Backend com Go & Gin • Demonstrações Práticas Compiláveis
💻 Código de Exemplo 01 — ShouldBindJSON com Struct Tags de Validação
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
type CriarUsuarioInput struct {
Nome string `json:"nome" binding:"required,min=3,max=80"`
Email string `json:"email" binding:"required,email"`
Idade int `json:"idade" binding:"gte=18,lte=120"`
}
func main() {
engine := gin.Default()
engine.POST("/usuarios", func(c *gin.Context) {
var input CriarUsuarioInput
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"erro": err.Error()})
return
}
c.JSON(http.StatusCreated, gin.H{
"mensagem": "usuário criado com sucesso",
"email": input.Email,
})
})
engine.Run(":8080")
}
💻 Código de Exemplo 02 — Binding de Query String e Upload Multipart
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
type FiltroBusca struct {
Termo string `form:"q" binding:"required"`
Limite int `form:"limit,default=10"`
}
func main() {
engine := gin.Default()
engine.GET("/buscar", func(c *gin.Context) {
var filtro FiltroBusca
if err := c.ShouldBindQuery(&filtro); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"erro": err.Error()})
return
}
c.JSON(http.StatusOK, filtro)
})
engine.POST("/usuarios/avatar", func(c *gin.Context) {
arquivo, err := c.FormFile("avatar")
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"erro": "arquivo 'avatar' ausente"})
return
}
destino := "uploads/" + arquivo.Filename
if err := c.SaveUploadedFile(arquivo, destino); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"erro": "falha ao salvar arquivo"})
return
}
c.JSON(http.StatusOK, gin.H{"arquivo_salvo": destino, "tamanho_bytes": arquivo.Size})
})
engine.Run(":8080")
}
💻 Código de Exemplo 03 — Validador Customizado e Formatador de Erros Amigável
package main
import (
"net/http"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/validator/v10"
)
type ErroCampo struct {
Campo string `json:"campo"`
Mensagem string `json:"mensagem"`
}
var validarCPF validator.Func = func(fl validator.FieldLevel) bool {
cpf := fl.Field().String()
return len(cpf) == 11
}
func registrarValidadores() {
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
v.RegisterValidation("valida_cpf", validarCPF)
}
}
func formatarErrosValidacao(err error) []ErroCampo {
var erros []ErroCampo
if valErrs, ok := err.(validator.ValidationErrors); ok {
for _, f := range valErrs {
erros = append(erros, ErroCampo{
Campo: f.Field(),
Mensagem: "campo '" + f.Field() + "' falhou na regra '" + f.Tag() + "'",
})
}
}
return erros
}
type CadastroClienteInput struct {
Nome string `json:"nome" binding:"required"`
CPF string `json:"cpf" binding:"required,valida_cpf"`
}
func main() {
registrarValidadores()
engine := gin.Default()
engine.POST("/clientes", func(c *gin.Context) {
var input CadastroClienteInput
if err := c.ShouldBindJSON(&input); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"erros": formatarErrosValidacao(err)})
return
}
c.JSON(http.StatusCreated, input)
})
engine.Run(":8080")
}