validator icon indicating copy to clipboard operation
validator copied to clipboard

Validation seems to fail for boolean 'false'

Open elfner opened this issue 4 years ago • 6 comments

Package version:

v10

Issue, Question or Enhancement:

Seems that validation fails on boolean types when value is passed as 'false', but works for 'true'. Appreciate any insight - thanks!

$ curl -s -X POST -H 'Content-Type: application/json' http://localhost:8080/doFoo -d '{"fieldx":true}'
{
    "fieldx": true
}
$ curl -s -X POST -H 'Content-Type: application/json' http://localhost:8080/doFoo -d '{"fieldx":false}'
{
    "message": "Key: 'something.Fieldx' Error:Field validation for 'Fieldx' failed on the 'required' tag"
}

Postman submission gives the same result.

Code sample, to showcase or reproduce:

package main

import (
	"net/http"
	"encoding/json"

	"github.com/go-playground/validator/v10"
	"github.com/labstack/echo/v4"
	"github.com/labstack/echo/v4/middleware"
)

type (
	CustomValidator struct {
		validator *validator.Validate
	}

	something struct {
                Fieldx  bool `json:"fieldx" validate:"required"`
	}
)

func (cv *CustomValidator) Validate(i interface{}) error {
	return cv.validator.Struct(i)
}

func doFoo (c echo.Context) (err error) {
	req := new(something)
	if err := c.Bind(req); err != nil {
		return echo.NewHTTPError(http.StatusBadRequest, err.Error())
	}
	if err := c.Validate(req); err != nil {
		return echo.NewHTTPError(http.StatusBadRequest, err.Error())
	}
	dataString, err := json.Marshal(req)
        if err != nil {
                return c.String(http.StatusBadRequest, "failed to marshal JSON")
        }
	return c.String(http.StatusOK, string(dataString))
}

func main() {
	e := echo.New()
	e.Validator = &CustomValidator{validator: validator.New()}

	// Middleware
	e.Use(middleware.Logger())
	e.Use(middleware.Recover())

	// Routes
	e.POST("/doFoo", doFoo)

	// Start server
	e.Logger.Fatal(e.Start(":8080"))
}

elfner avatar Jan 04 '21 19:01 elfner

the same issue

4n70w4 avatar Jun 03 '21 14:06 4n70w4

by default required will fail when the value is zero value. so with that in mind, it makes sense to fail on false

however, if true and false are valid values then you don't really need a validate:"required" tag at all

see https://pkg.go.dev/gopkg.in/go-playground/validator.v10#hdr-Required

joebartels avatar Jun 04 '21 20:06 joebartels

Same issue here. validate:"boolean" fails whichever value (true/false) is passed in a json request

pintobikez avatar Dec 10 '21 22:12 pintobikez

Same issue here. validate:"boolean" fails whichever value (true/false) is passed in a json request

I am having the same issue.

9r1nc3w1ll avatar May 29 '22 22:05 9r1nc3w1ll

Same issue here. validate:"boolean" fails whichever value (true/false) is passed in a json request

I am having the same issue.

Me too. Anyone can help me?

MuShaf-NMS avatar Jun 09 '22 11:06 MuShaf-NMS

Forgive the short reply, answering from phone.

Please read the documentation for required and it should make sense why false fails the required check AND this was explained above by @joebartels

Please let me know if I’m missing something and something else is wrong.

deankarn avatar Jun 09 '22 14:06 deankarn

If you want to validate that the value is present you will have to use a pointer there.

So for the example given, the change should be something like this.

	something struct {
-               Fieldx  bool `json:"fieldx" validate:"required"`
+               Fieldx  *bool `json:"fieldx" validate:"required"`
	}

I will close this as answered.

zemzale avatar Sep 05 '22 07:09 zemzale

You can use this way:

Name  *bool `json:"name" validate:"required"`

Use a pointer

thanks @zemzale

vansenic avatar Jan 08 '23 06:01 vansenic

by default required will fail when the value is zero value. so with that in mind, it makes sense to fail on false

however, if true and false are valid values then you don't really need a validate:"required" tag at all

see https://pkg.go.dev/gopkg.in/go-playground/validator.v10#hdr-Required

This is extremely dangerous because if a caller forgets/does not to specify a field when it is required by contract then it would lead to unintended consequences.

This is very bad design.

SharkFourSix avatar Mar 27 '23 23:03 SharkFourSix

@SharkFourSix not sure how long you’ve been using Go but there is no concept of an uninitialized variable and so ever variable will get a default value including when unmarshalling data into a struct.

and so to that end there are two options:

  1. Design so the default types work in your favour eg. If not present the default makes sense.(which is good design in and language)
  2. Provide the ability to detect the difference between presence and default values. This can be done in several ways including using a pointer and using a Nullable type like sql.NullBool or equivalent to keep this on the stack when possible in concert with Registering the custom type with validator.

I think you may be confusing bad design with the facts and semantics of the Go language. I would be glad to be wrong but as far as I know there is no other way to detect presence vs default.

deankarn avatar Mar 28 '23 00:03 deankarn

@deankarn

Well, at the same time, it doesn't make sense to treat false as bad input because it's just as important as any other value.

That right there is where the bad design is. Without even looking at semantics or language behavior.

Assignment of default values to uninitialized variables is not exclusive to go. So this is not a problem with the underlying language.

You want to leave that behavior to the language and let it do what it does (throw a null pointer exception or panic or whatever or assign whatever initialization value the compiler may decide) because then and only then will the programmer realize that they did not provide a value to that value, instead of the library hijacking that behavior because it decided to interpret certain valid values as if the memory/variable containing that said value doesn't exist, which again, is bad design.

Also, it's not like the library is allocating the memory for me to worry about initialization. That's my business, not the library's.

SharkFourSix avatar Mar 28 '23 07:03 SharkFourSix

@deankarn @SharkFourSix I absolutely agree with SharkFourSix. While for strings this might make sense, it doesn't even make sense for integers, much less for booleans. I'm not arguing the design of Golang here, I'm arguing that to my brain the tag required implies just that the field needs to be in the json I'm verifying, not that it has to have a certain value. And requiring one to use a pointer when one does not need a pointer just in order to make sense of a tag is just puting the cart before the horse.

npropadovic avatar Sep 26 '23 07:09 npropadovic