确定POST数据值是否与结构字段类型匹配

Using the gin framework I am trying to determine if POST'ed data does not match the struct field type and inform API user of their error.

type CreateApp struct {
    LearnMoreImage string `db:"learn_more_image" json:"learn_more_image,omitempty" valid:"string,omitempty"`
    ApiVersion     int64  `db:"api_version" json:"api_version" valid:"int,omitempty"`
}
...
func CreateApps(c *gin.Context) {
    var json models.CreateApp
    c.Bind(&json)

So when I POST

curl -H "Content-Type: application/json" -d '{"learn_more_image":"someimage.jpg","api_version":"somestring"}' "http://127.0.0.1:8080/v1.0/apps"

I would like to determine whether the POST'ed data for field 'api_version' (passed as string) does not match the struct field it is being binded to (int). If the data doesnt match I'd like to send a message back to the user. Its for this reason I was hoping I could loop through the gin contexts data and check it.

The gin function 'c.Bind()' seems to omit invalid data and all subsequent data fields with it.

Gin has a built-in validation engine: https://github.com/bluesuncorp/validator/blob/v5/baked_in.go

but you can use your own or disable it completely.

The validator does not validate the wire data (json string), instead it validates the binded struct:

LearnMoreImage string `db:"learn_more_image" json:"learn_more_image,omitempty" binding:"required"`
ApiVersion     int64  `db:"api_version" json:"api_version" binding:"required,min=1"`

Notice this: binding:"required,min=1"

Then:

err := c.Bind(&json)

or use a middleware and read c.Errors.

UPDATED:

Three workarounds:

  • Validate the json string your own (it can not be done with enconding/json)
  • Validate if integer is > 0 binding:"min=1"
  • Use a map[string]interface{} instead of a Struct, then validate the type.

    func endpoint(c *gin.Context) {
        var json map[string]interface{}
        c.Bind(&json)
        struct, ok := validateCreateApp(json)
        if ok { /** DO SOMETHING */ }
    }
    
    func validateCreateApp(json map[string]interface{}) (CreateApp, bool) {
        learn_more_image, ok := json["learn_more_image"].(string)
        if !ok {
            return CreateApp{}, false
        }
        api_version, ok = json["api_version"].(int)
        if !ok {
            return CreateApp{}, false
        }
        return CreateApp{
            learn_more_image, api_version,
        }
    }