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")
}