Как вернуть пользовательскую ошибку, если проверка завершилась неудачно с Gin - PullRequest
0 голосов
/ 25 мая 2018

Например, у меня есть следующее 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, что я отметил в теге structs json:"city".Поэтому мой вопрос: правильно ли я выбрал способ решения проблемы, если ответ «да», как получить структуры json tag для поля?

Ответы [ 2 ]

0 голосов
/ 25 мая 2018

Если вы хотите, чтобы он был таким же, как определено в вашем теге 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 в этом поле).

0 голосов
/ 25 мая 2018

Вы можете использовать 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
}
...