type Req struct {
    Field int `json:"field" binding:"required"`
}

func handler(ctx *gin.Context) {
    req := &Req{}
    err := ctx.BindJSON(&req)
}
"Key: 'Req.Field' Error:Field validation for 'Field' failed on the 'required' tag"

So how to avoid the error if I need to parse {"field":0} ?

Comment From: deankarn

duplicate, this has been answered many times: https://github.com/gin-gonic/gin/issues/690 https://github.com/gin-gonic/gin/issues/659 https://github.com/gin-gonic/gin/issues/611 https://github.com/gin-gonic/gin/issues/491

in short the validation is run after the data is unmarshalled into the struct and so even though Field in your example was not posted because of Go's static nature there will still be a default value and required checks that it's not the default value....the way to do this is to make int a pointer *int that way the default value is nil vs 0 and so when the value is not posted required will work as you expect.

Comment From: rstrlcpy

Thanks. It would be nice if someone added several notes about this to documentation.

Comment From: appleboy

Answer:

type Req struct {
-    Field int `json:"field" binding:"required"`
+    Field *int `json:"field" binding:"exists"`
}

Comment From: elSuperRiton

I've tried switching to pointers value for int + changing my bindings to exists but somehow the BindWithJSON function still crashes when binding from JSON with a request where values of type *int (or int) start with 0. I just can't wrap my head around how to solve this.

My structs look like this :

type User struct {
    gorm.Model
    Firstname string    `json:"firstname" binding:"required"`
    Lastname  string    `json:"lastname" binding:"required"`
    Email     string    `json:"email" binding:"required" gorm:"unique"`
    Password  string    `json:"password" binding:"required"`
    Phones    Phones    `gorm:"-" json:"phones" binding:"gt=0,dive"`
    Addresses Addresses `gorm:"-" json:"addresses" binding:"gt=0,dive"`
}

type Phone struct {
    gorm.Model
    UserID      uint64
    PhonePOID   *int `json:"phone_poid" binding:"exists, numeric"`
    PhoneNumber *int `json:"phone_number" binding:"exists, numeric"`
    Main        bool `json:"main"`
}

Comment From: decipherpunk

I create a simple to debug my actual application which is hitting a blocker:

Here is my form :

package form

type TestForm struct {
    Age int `form:age" json:"age" binding:"exists"`
    FirstName string `form:"firstname" json:"firstname" binding:"required"`
    LastName string `form:"lastname" json:"lastname" binding:"required"`
    Password string `form:"password" json:"password" binding:"required"`
}

HTML Form

<form role="form" id="config" method="post" action="/v1/api/config/test/set">
        <div class="form-group">
            <label  for="age">age</label>
            <input type="number" name="age" class="form-control" id="age"  readonly>
        </div>
        <div class="form-group">
            <label class="required-pf" for="firstname">firstname</label>
            <input type="text" name="firstname" class="form-control" id="firstname" required>
        </div>
        <div class="form-group">
            <label  class="required-pf" for="lastname">lastname</label>
            <input type="text" name="lastname" class="form-control" id="lastname" required>
        </div>
        <div class="form-group">
            <label  class="required-pf" for="password">Password</label>
            <input type="password" name="password" class="form-control" id="password" required>
        </div>
        <button type="submit" class="btn btn-default">Save Configuration</button>
    </form>

Controller

func (ctrl TestController) TestConfig(c *gin.Context){
    var testForm form.TestForm
    if c.ShouldBindWith(&testForm, binding.FormPost) != nil {
        c.Redirect(302, "/v1/console/config/request_failed")
    }
    TestModel.TestConfig(testForm)
    fmt.Println(testForm.age)
    c.Redirect(302, "/v1/console/config/success")
}

And a model test save into a json file

func (m TestModel) ServerConfig(form form.TestForm) (){
    jsonFile, err := os.Open("config/dev.json")
    if err != nil {
        fmt.Println(err)
    }
    defer jsonFile.Close()
    data, _ := ioutil.ReadAll(jsonFile)
    age, _ := sjson.Set(string(data), "app.age", form.Age)
    fmt.Println(form.age) // returns 0
    firstName, _ := sjson.Set(age, "app.firstname", form.FirstName)
    lastName, _ := sjson.Set(firstName, "app.lastname", form.LastName)
    secret, _ := sjson.Set(lastName, "app.secret", form.Secret)
    err = ioutil.WriteFile("config/dev.json", []byte(secret), 0644)
}

Not sure what's happening but form always ends up providing 0 for age regardless of the actual input.

I am seriously lost, not sure what i am doing wrong all the form fields work except the one with int.

Comment From: LaysDragon

@deankarn I can understand why we need use pointer with binding required validator because of golang's nature, but it is really counterintuitive for most people read the quick start from the gin README.md tutorial,it make me expected it only validating on the source data and failed while json missed the field. But it not,it actually working on the unmarshalled struct make it have it's limit(it lost the raw data struct while them unmarshalled into a struct and those lost field turn into zero value and ambiguity with real value).

I feeling it is dangerous while people write code with what they really expected from readme's example because of the json/xml/anything-else's dynamic compare to golang static stuct. It might be better if this behavior can mention on the readme about how required tag working.

Meanwhile,I thought that validator require to change the original data struct to make work is strange,isn't that golang's struct meta tag coming for slove? Since the validator give me the an expected that it is is extra functions to validate on source data(whenin gin),the requirement of pointer break the data struct's design and struct tag's intention..

Like I using the openapi generator.the pointer is decide via the field's attr,if I hope to to share code with go gin,I have to rewrite the generator's template to make every field a pointer,that really not a good solution

Other situation is use with other framework like gorm,I don't really want to make everything into pointer just because of gin validator's limit,or need to matain the same copy struct from the share one. Hope if there any workaround to made gin validator working on source data(json/xml/...) instead of the unmarshalled struct while I use the gin framework for such situation.

Comment From: deankarn

@LaysDragon please don't post on closed issues, create a new one and reference. 😄

As for the Gin documentation, will leave that to the Gin authors. As for validator there is no way besides: - Having pointer - Using a nullable type eg. sql.NullString and those types can be used with validator if register just like here

For context validator on purpose does not validate the source data but struct and field data so that it doesn't matter where the source data came from eg. manually created, Form Post, Database...... I'm sure there are other way to validate the source data but are outside the use case of validator

The reality is to capture that undefined/nil/null state you have to account for it using a pointer, custom type or interface{] which is arguably still a pointer.

Comment From: toudi

I just stumbled upon this issue today and the highlighted response suggested using exists validator, however this validation function no longer exists (oh, the irony :)). Anyhow, the short answer is, as somebody pointed out already is to use a pointer with required validator, like so:

type MyModel struct {
    MyField *int `json:"my_field" binding:"required"`
}

func MyFunction(c *gin.Context) {
    var myModel MyModel;
    err := c.shouldBind(&myModel);

    // the rest of the logic 
    // - if you do want to use the int value, you have to de-reference it, like so:

    var myIntValue = *myModel.MyField
}

Comment From: nuffin

duplicate, this has been answered many times: #690 #659 #611 #491

in short the validation is run after the data is unmarshalled into the struct and so even though Field in your example was not posted because of Go's static nature there will still be a default value and required checks that it's not the default value....the way to do this is to make int a pointer *int that way the default value is nil vs 0 and so when the value is not posted required will work as you expect.

asked many times, but still "works". it's fine

I'm using pointer too, and sometimes failed with "required" binding, not every try with the same request.

Comment From: nuffin

I just stumbled upon this issue today and the highlighted response suggested using exists validator, however this validation function no longer exists (oh, the irony :)). Anyhow, the short answer is, as somebody pointed out already is to use a pointer with required validator, like so:

``go type MyModel struct { MyField *intjson:"my_field" binding:"required"` }

func MyFunction(c *gin.Context) { var myModel MyModel; err := c.shouldBind(&myModel);

// the rest of the logic 
// - if you do want to use the int value, you have to de-reference it, like so:

var myIntValue = *myModel.MyField

} ```

exists does not exist :D

Comment From: MrNocTV

Answer:

diff type Req struct { - Field int `json:"field" binding:"required"` + Field *int `json:"field" binding:"exists"` }

It should be required

Comment From: danielalexis

"exists" no longer exists on the package gopkg.in/go-playground/validator so it doesn't work anymore. https://pkg.go.dev/github.com/go-playground/validator/v10@v10.16.0

If you are working with positive integers I would recommend gte=0

Comment From: piti118

as @MrNocTV mentioned PSA: for those of you who got to this issue in 2024 and beyond. exists is no longer supported in validator. It should be

diff type Req struct { - Field int `json:"field" binding:"required"` + Field *int `json:"field" binding:"required"` }

Comment From: mrcleanandfresh

I was experiencing an issue with boolean values; without the fix, the validator was saying that my boolean wasn't present. I had to use:

type Req struct {
  Field *bool `json:"field" binding:"required"`
}

This may be a Golang 101 question, so bear with me: When this request comes into Gin, via the Request.Body which I'm assuming is like a byte stream that needs to be opened, read, and mapped, when doing c.BindJSON. In that byte stream (or whatever is happening), are the booleans represented by binary 0 or 1 values that must be mapped to false or true depending on the type of the struct?

Why is it necessary to throw that pointer on there to make it work?