Skip to content

gin-validation for an array of struct #41

@NishantG01

Description

@NishantG01

Hi @depado ,
Greetings, I saw your blog for gin-validation and it helped in my use case.
But I am unable to use it if the validation is done on an array of struct.

My sample code

package main

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"reflect"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/go-playground/validator/v10"
)

type User struct {
	Email string `json:"email" form:"e-mail" binding:"required"`
	Name  string `json:"name" binding:"required"`
}

func main() {
	route := gin.Default()
	if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
		v.RegisterTagNameFunc(func(fld reflect.StructField) string {
			name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0]
			if name == "-" {
				return ""
			}
			return name
		})
	}
	route.POST("/user", validateUser)
	route.Run(":8085")
}
func validateUser(c *gin.Context) {
	var u []User
	if err := c.ShouldBindJSON(&u); err == nil {
		c.JSON(http.StatusOK, gin.H{"message": "User validation successful."})
	} else {
		fmt.Println(err)
		var verr validator.ValidationErrors
		var jsErr *json.UnmarshalTypeError

		if errors.As(err, &verr) {
			c.JSON(http.StatusBadRequest, gin.H{"errors": Descriptive(verr)})
			return
		} else if errors.As(err, &jsErr) {
			c.JSON(http.StatusBadRequest, gin.H{"errors": MarshalErr(*jsErr)})
			return
		}
	}
}

func Simple(verr validator.ValidationErrors) map[string]string {
	errs := make(map[string]string)
	for _, f := range verr {
		err := f.ActualTag()

		if f.Param() != "" {
			err = fmt.Sprintf("%s=%s", err, f.Param())
		}
		errs[f.Field()] = err + "," + f.Kind().String()
		fmt.Println(errs)
	}
	return errs

}

type ValidationError struct {
	Field  string `json:"field"`
	Type   string `json:"type"`
	Reason string `json:"reason"`
}
func MarshalErr(jsErr json.UnmarshalTypeError) ValidationError {
	errs := ValidationError{}
	errs.Field=jsErr.Field
	errs.Reason="invalid type"
	errs.Type=jsErr.Type.String()
	return errs
}
func Descriptive(verr validator.ValidationErrors) []ValidationError {
	errs := []ValidationError{}

	for _, f := range verr {
		fmt.Println(f)
		err := f.ActualTag()
		if f.Param() != "" {
			err = fmt.Sprintf("%s=%s", err, f.Param())
		}
		errs = append(errs, ValidationError{Field: f.Field(), Reason: err, Type: f.Type().Name()})
	}

	return errs
}

Test Input

curl --location --request POST 'http://localhost:8085/user' \
--header 'content-type: application/json' \
--data-raw '[
    {
        "email": "[email protected]",
        "name": "Me"
    },
    {
        "email": "[email protected]"
    }
]'

Expected output

"errors": [
        {
            "field": "name",
            "type": "string",
            "reason": "required"
        }
    ]

Can you please help me with it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions