bugfix> go > 投稿

たとえば、次の 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タグを取得する方法ですか?

回答 2 件
  • 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
    }
    
    

  • 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タグがないか)を確認する必要があります。

あなたの答え