例如,我有以下struct
type Address struct {
City string `json:"city" binding:"required"`
AddressLine string `json:"address_line" binding:"required"`
}
我有以下功能来处理来自用户的请求
func AddressCreate(c *gin.Context) {
var address Address
if err := c.BindJSON(&address); err == nil {
// if everything is good save to database
// and return success message
db.Create(&address)
c.JSON(http.StatusOK, gin.H {"status":"success"})
} else {
c.JSON(http.StatusBadRequest, err)
}
}
预期的行为是以这种方式返回json
[
{
"city":"required"
}
{
"address_line":"required"
}
]
但我收到的错误格式如下
"Address.City": {
"FieldNamespace": "Address.City",
"NameNamespace": "City",
"Field": "City",
"Name": "City",
"Tag": "required",
"ActualTag": "required",
"Kind": 24,
"Type": {},
"Param": "",
"Value": ""
},
"Address.AddressLine": {
"FieldNamespace": "AddressLine",
"NameNamespace": "AddressLine",
"Field": "AddressLine",
"Name": "AddressLine",
"Tag": "required",
"ActualTag": "required",
"Kind": 24,
"Type": {},
"Param": "",
"Value": ""
}
我尝试了什么:
我创建了将error
转换为ValidationErrors
并迭代其中所有FieldError
的函数
func ListOfErrors(e error) []map[string]string {
ve := e.(validator.ValidationErrors)
InvalidFields := make([]map[string]string, 0)
for _, e := range ve {
errors := map[string]string{}
// field := reflect.TypeOf(e.NameNamespace)
errors[e.Name] = e.Tag
InvalidFields = append(InvalidFields, errors)
}
return InvalidFields
}
输出看起来好多了
[
{
"City":"required"
},
{
"AddressLine":"required"
}
]
但我无法用字段的名称解决问题。我无法将Name
交换为我在结构标记name
中注明的json:"city"
。所以我的问题是,如果答案是肯定的,那么我选择正确的方法来解决问题如何获取字段的结构json标签?
答案 0 :(得分:0)
您可以使用ToSnake
来篡改名称:
import (
"unicode"
)
// ToSnake convert the given string to snake case following the Golang format:
// acronyms are converted to lower-case and preceded by an underscore.
func ToSnake(in string) string {
runes := []rune(in)
length := len(runes)
var out []rune
for i := 0; i < length; i++ {
if i > 0 && unicode.IsUpper(runes[i]) && ((i+1 < length && unicode.IsLower(runes[i+1])) || unicode.IsLower(runes[i-1])) {
out = append(out, '_')
}
out = append(out, unicode.ToLower(runes[i]))
}
return string(out)
}
func ListOfErrors(e error) []map[string]string {
ve := e.(validator.ValidationErrors)
invalidFields := make([]map[string]string, 0)
for _, e := range ve {
errors := map[string]string{}
errors[ToSnake(e.Name)] = e.Tag
invalidFields = append(InvalidFields, errors)
}
return invalidFields
}
答案 1 :(得分:0)
如果您希望它与json标记中定义的相同,那么您应该使用反射从数据类型中提取该标记。
我没有您的图书馆,因此无法编辑和检查它。但我相信你所追求的应该是这样的:
func ListOfErrors(address *Address, e error) []map[string]string {
ve := e.(validator.ValidationErrors)
InvalidFields := make([]map[string]string, 0)
for _, e := range ve {
errors := map[string]string{}
// field := reflect.TypeOf(e.NameNamespace)
field, _ := reflect.TypeOf(address).Elem().FieldByName(e.Name)
jsonTag := string(field.Tag.Get("json"))
errors[jsonTag] = e.Tag
InvalidFields = append(InvalidFields, errors)
}
return InvalidFields
}
请注意,由于address
参数的类型基本上已知,因此有点人为。因此,并非严格要求作为函数参数。但您可以将address *Address
更改为address interface{}
,并将其用于其他类型。
免责声明:为简洁起见,我跳过错误检查,但您当然应该检查代码中的错误(例如,没有此类字段错误或该字段上没有json标记)。