Validação de Dados em GO com gookit/validate
No universo de JavaScript uma das bibliotecas mais populares para validação de dados com certeza é o zod, mas quando iniciei meus estudos em GO vi que a forma de validar os dados de forma nativa era um tanto quanto engessada.
Após muita pesquisa encontrei um pacote para GO chamado gookit/validate, uma forma muito mais prática e simples de validar os dados, porém ainda não era completamente o que eu estava buscando. Eu queria algo que trouxesse uma experiência de desenvolvimento mais simples e com um código ainda reutilizável. Para isso desenvolvi um validador de dados utilizando como core o gookit/validate.
Neste artigo apresento o meu validador e como utilizá-lo de forma simples em um handler que será posteriormente utilizado em uma chamada HTTP para validar os dados de entrada do usuário.
1 — Struct:
type NewValidator struct {
Data interface{}
Validator *validate.Validation
}
A propriedade Data como o próprio nome já diz irá armazenar os dados que serão validados. O Validator irá armazenar o validate do pacote gookit/validate para ser utilizado nas validações posteriormente.
2 — Initializer:
func (nv *NewValidator) Initializer() {
v := validate.Struct(nv.Data)
v.StopOnError = false
nv.Validator = v
}
O Initializer serve para adicionar os dados que serão validados para o validate, utilizando o método Struct. Também utilizei o método StopOnError passando o valor false para ele. Este método serve para definir se iremos retornar todos ou apenas um erro por vez, essa configuração influencia no uso do método All() do Validator. Por fim é atribuído o validate criado para a propriedade Validator do struct NewValidator.
3 — Método GetErrors
func (nv *NewValidator) GetErrors() []string {
v := nv.Validator
errors_msg := []string{}
for field := range v.Errors.All() {
errors := v.Errors.Field(field)
for _, err := range errors {
errors_msg = append(errors_msg, err)
}
}
return errors_msg
}
O método GetErrors é muito simples e serve para retornar todos os erros dos campos que foram validados.
A variável v armazena o Validator que será utilizado para extrair os erros dos campos. Com isso, utilizando o método All() a partir de v.Errors é feita uma iteração sobre o map retornado por esse método.
O field em questão retorna a key para acessarmos o map de erros do campo que estamos extraindo as mensagens de erro, logo, temos uma nova variável chamada errors que armazena um map de erros do campo, utilizando o método Fields() a partir de v.Errors passando como valor a key do map.
Após esta etapa é feita uma nova iteração agora na variável errors, e, então é armazenado cada string retornada no array da variável errors_msg criada antes do primeiro laço for.
Por fim, o método GetErrors retorna a variável errors_msg a qual contém todas as mensagens de erro extraídas.
Validações
Os campos que serão validados devem ser adicionados no struct, conforme o exemplo:
type ProductDto struct {
Name string `json:"name" validate:"required" message:"O nome do produto é obrigatório"`
Description string `json:"description"`
Price float64 `json:"price" validate:"required|float|min:1" message:"O preço do produto é obrigatório"`
}
Caso de Uso
body := models.ProductDto{}
if err := context.BindJSON(&body); err != nil {
return models.Product{}, models.NewError("Server Erro", http.StatusInternalServerError, []string{})
}
v := utils.NewValidator{Data: body}
v.Initializer()
if (!v.Validator.Validate()) {
return models.Product{}, models.NewError("Fields Validation Error", http.StatusBadRequest, v.GetErrors())
}
No exemplo acima foi criada a variável body a qual irá armazenar os dados enviados pelo usuário no corpo da requisição. Essa variável precisa ser do tipo struct criado anteriormente, neste caso o ProductsDTO. Após isso, é criada a variável v que irá armazenar o nosso validator para ser utilizado nas validações dos dados enviados pelo usuário.
O método Validate está sendo utilizado para validar se há algum erro de validação, este método retorna true ou false.
Por fim, para retornar a lista de erros, basta chamar o método GetErrors.
Gostou? Tem alguma outra ideia? Deixe seu comentário.