go-playground / validator

:100:Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving
MIT License
16.53k stars 1.31k forks source link

How to customize the structure name in the returned errors? #1067

Closed devhaozi closed 8 months ago

devhaozi commented 1 year ago

Package version eg. v9, v10:

v10

Issue, Question or Enhancement:

How to customize the structure name in the returned errors.

After doing nothing and using translate, the return errors will be like this:

msg: {
  "User.email": "email必须为有效的邮箱",
  "User.id": "id为必填字段"
}

Such errors are not friendly enough for the front-end display, because two languages are mixed. I already see #524 and #633, so I try to add:

validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
    return fld.Tag.Get("comment")
})

func removeTopStruct(fields map[string]string) map[string]string {
    res := map[string]string{}
    for field, err := range fields {
        res[field[strings.Index(field, ".")+1:]] = err
    }
    return res
}

But it will also replace the key name in the errors, like:

msg: {
  "邮箱": "邮箱必须为有效的邮箱",
  "用户id": "用户id为必填字段"
}

I want this:

msg: {
  "email": "邮箱必须为有效的邮箱",
  "id": "用户id为必填字段"
}

Is there any magic functions to fix this question?

Code sample, to showcase or reproduce:

type User struct {
    email string `validate:"required" json:"province" comment:"邮箱"`
    id     string `validate:"required" json:"city" comment:"用户id"`
}

uni := ut.New(en.New(), en.New())
trans, _ := uni.GetTranslator("zh")

validate := validator.New()

// Get the comment tag, which is used to replace the field name
validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
    return fld.Tag.Get("comment")
})

err := zh.RegisterDefaultTranslations(validate, trans)
err = validate.Struct(data)

if err != nil {
    errs := err.(validator.ValidationErrors)
    return removeTopStruct(errs.Translate(trans))
}

// removeTopStruct remove the top struct, like: User.id => id
func removeTopStruct(fields map[string]string) map[string]string {
    res := map[string]string{}
    for field, err := range fields {
        res[field[strings.Index(field, ".")+1:]] = err
    }
    return res
}
HubQin commented 1 year ago

I come accross this problem,too. thanks for you removeTopStruct. Could any one help to have a look at the other one problem?

HaoFun commented 1 year ago

Hi! can try here

cmxStarCoding commented 8 months ago

你好,也许可以使用我的例子来解决这个问题 image

// core/validator/user_validator.go

package validator

import (
    "fmt"
    "github.com/gin-gonic/gin"
    ut "github.com/go-playground/universal-translator"
    "gopkg.in/go-playground/validator.v9"
    "reflect"
)

type UserLoginRequest struct {
    //Username string `json:"username" binding:"required,min=4,max=20"`
    //Phone   string  `json:"phone" form:"phone" validate:"required,email"`
    Phone    string  `json:"phone" form:"phone" validate:"required" comment:"手机号"`
    Password string  `json:"password" form:"password" validate:"required,min=6"`
}

func ValidateUserLogin(c *gin.Context) (*UserLoginRequest, error) {
    var request UserLoginRequest
    utTrans := c.Value("Trans").(ut.Translator)

    Validate, _ := c.Get("Validate")
    validatorInstance, _ := Validate.(*validator.Validate)

    if err := c.ShouldBindJSON(&request); err != nil {
        return nil,err
    }
    // 收集结构体中的comment标签,用于替换英文字段名称,这样返回错误就能展示中文字段名称了
    validatorInstance.RegisterTagNameFunc(func(fld reflect.StructField) string {
        return fld.Tag.Get("comment")
    })
    //自定义错误语句
    //validatorInstance.RegisterTranslation("required", utTrans, func(ut ut.Translator) error {
    //  return ut.Add("required", "{0} 哈哈哈!", true) // see universal-translator for details
    //}, func(ut ut.Translator, fe validator.FieldError) string {
    //  t, _ := ut.T("required", fe.Field())
    //  return t
    //})

    //validatorInstance.RegisterTranslation(
    //  "email",
    //  utTrans,
    //  func(ut ut.Translator) error {
    //      return ut.Add("email", "{0}格式不正确", true)
    //  },
    //  func(ut ut.Translator, fe validator.FieldError) string {
    //      t, _ := ut.T("email", fe.Field())
    //      return t
    //  },
    //)

    // 进行进一步的验证
    err := validatorInstance.Struct(request) //这里的err是未翻译之前的
    if  err != nil {
        errs := err.(validator.ValidationErrors)
        var sliceErrs []string
        for _, e := range errs {
            sliceErrs = append(sliceErrs, e.Translate(utTrans))
        }
        return nil,fmt.Errorf(sliceErrs[0])
    }

    return &request,nil
}