Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to do gin-validation for an array of struct #40

Open
NishantG01 opened this issue Aug 6, 2021 · 0 comments
Open

How to do gin-validation for an array of struct #40

NishantG01 opened this issue Aug 6, 2021 · 0 comments

Comments

@NishantG01
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant