Update to return FieldValidationError for single field validation

update to return FieldValidationError for single field validation
add Kind, Param and Value to the FieldValidationError struct to allow
for a more automated error handling api outside of this library.
pull/16/head
Dean Karn 10 years ago
parent 550287f7c6
commit ac82433503
  1. 4
      doc.go
  2. 88
      validator.go
  3. 92
      validator_test.go

@ -8,7 +8,7 @@ but you may also create a new instance if needed.
// built in
errs := validator.ValidateStruct(//your struct)
errs := validator.ValidateFieldByTag(field, "omitempty,min=1,max=10")
valErr := validator.ValidateFieldByTag(field, "omitempty,min=1,max=10")
// new
newValidator = validator.New("struct tag name", validator.BakedInFunctions)
@ -57,7 +57,7 @@ intended use is for development + debugging, not a production error message.
Why not a better error message? because this library intends for you to handle your own error messages
Why should I handle my own errors? Many reasons, for me building and internationalized application
Why should I handle my own errors? Many reasons, for me building an internationalized application
I needed to know the field and what validation failed so that I could provide an error in the users specific language.
if fieldErr.Field == "Name" {

@ -27,6 +27,9 @@ const (
type FieldValidationError struct {
Field string
ErrorTag string
Kind reflect.Kind
Param string
Value interface{}
}
// This is intended for use in development + debugging and not intended to be a production error message.
@ -220,7 +223,7 @@ func (v *Validator) ValidateStruct(s interface{}) *StructValidationErrors {
default:
if fieldError := v.validateStructFieldByTag(valueField.Interface(), typeField.Name, tag); fieldError != nil {
if fieldError := v.validateFieldByNameAndTag(valueField.Interface(), typeField.Name, tag); fieldError != nil {
validationErrors.Errors[fieldError.Field] = fieldError
// free up memory reference
fieldError = nil
@ -235,32 +238,19 @@ func (v *Validator) ValidateStruct(s interface{}) *StructValidationErrors {
return validationErrors
}
// ValidateFieldWithTag validates the given field by the given tag arguments
func (v *Validator) validateStructFieldByTag(f interface{}, name string, tag string) *FieldValidationError {
if err := v.validateFieldByNameAndTag(f, name, tag); err != nil {
return &FieldValidationError{
Field: name,
ErrorTag: err.Error(),
}
}
return nil
}
// ValidateFieldByTag allows validation of a single field with the internal validator, still using tag style validation to check multiple errors
func ValidateFieldByTag(f interface{}, tag string) error {
func ValidateFieldByTag(f interface{}, tag string) *FieldValidationError {
return internalValidator.validateFieldByNameAndTag(f, "", tag)
}
// ValidateFieldByTag allows validation of a single field, still using tag style validation to check multiple errors
func (v *Validator) ValidateFieldByTag(f interface{}, tag string) error {
func (v *Validator) ValidateFieldByTag(f interface{}, tag string) *FieldValidationError {
return v.validateFieldByNameAndTag(f, "", tag)
}
func (v *Validator) validateFieldByNameAndTag(f interface{}, name string, tag string) error {
func (v *Validator) validateFieldByNameAndTag(f interface{}, name string, tag string) *FieldValidationError {
// This is a double check if coming from ValidateStruct but need to be here in case function is called directly
if tag == "-" {
@ -283,7 +273,8 @@ func (v *Validator) validateFieldByNameAndTag(f interface{}, name string, tag st
panic("Invalid field passed to ValidateFieldWithTag")
}
// TODO: validate commas in regex's
var valErr *FieldValidationError
var err error
valTags := strings.Split(tag, ",")
for _, valTag := range valTags {
@ -296,62 +287,35 @@ func (v *Validator) validateFieldByNameAndTag(f interface{}, name string, tag st
for _, val := range orVals {
key, err := v.validateFieldByNameAndSingleTag(f, name, val)
valErr, err = v.validateFieldByNameAndSingleTag(f, name, val)
if err == nil {
return nil
}
errTag += "|" + key
errTag += "|" + valErr.ErrorTag
}
errTag = strings.TrimLeft(errTag, "|")
return errors.New(errTag)
}
valErr.ErrorTag = errTag
valErr.Kind = valueField.Kind()
if _, err := v.validateFieldByNameAndSingleTag(f, name, valTag); err != nil {
return err
return valErr
}
// TODO: validate = in regex's
// vals := strings.Split(valTag, "=")
// key := strings.Trim(vals[0], " ")
//
// if len(key) == 0 {
// panic(fmt.Sprintf("Invalid validation tag on field %s", name))
// }
//
// // OK to continue because we checked it's existance before getting into this loop
// if key == omitempty {
// continue
// }
//
// valFunc, ok := v.validationFuncs[key]
// if !ok {
// panic(fmt.Sprintf("Undefined validation function on field %s", name))
// }
//
// param := ""
// if len(vals) > 1 {
// param = strings.Trim(vals[1], " ")
// }
//
// if err := valFunc(f, param); !err {
//
// return errors.New(key)
// }
// if err := v.validateFieldByNameAndSingleTag(f, name, valTag); err != nil {
// return err
// }
if valErr, err = v.validateFieldByNameAndSingleTag(f, name, valTag); err != nil {
valErr.Kind = valueField.Kind()
return valErr
}
}
return nil
}
func (v *Validator) validateFieldByNameAndSingleTag(f interface{}, name string, valTag string) (string, error) {
func (v *Validator) validateFieldByNameAndSingleTag(f interface{}, name string, valTag string) (*FieldValidationError, error) {
vals := strings.Split(valTag, "=")
key := strings.Trim(vals[0], " ")
@ -360,9 +324,16 @@ func (v *Validator) validateFieldByNameAndSingleTag(f interface{}, name string,
panic(fmt.Sprintf("Invalid validation tag on field %s", name))
}
valErr := &FieldValidationError{
Field: name,
ErrorTag: key,
Value: f,
Param: "",
}
// OK to continue because we checked it's existance before getting into this loop
if key == omitempty {
return key, nil
return valErr, nil
}
valFunc, ok := v.validationFuncs[key]
@ -376,8 +347,9 @@ func (v *Validator) validateFieldByNameAndSingleTag(f interface{}, name string,
}
if err := valFunc(f, param); !err {
return key, errors.New(key)
valErr.Param = param
return valErr, errors.New(key)
}
return key, nil
return valErr, nil
}

@ -169,7 +169,7 @@ func (ms *MySuite) TestUrl(c *C) {
c.Assert(err, IsNil)
} else {
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "url")
c.Assert(err.ErrorTag, Equals, "url")
}
}
}
@ -222,7 +222,7 @@ func (ms *MySuite) TestUri(c *C) {
c.Assert(err, IsNil)
} else {
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "uri")
c.Assert(err.ErrorTag, Equals, "uri")
}
}
}
@ -239,12 +239,12 @@ func (ms *MySuite) TestOrTag(c *C) {
s = "this ain't right"
err = validator.ValidateFieldByTag(s, "rgb|rgba")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "rgb|rgba")
c.Assert(err.ErrorTag, Equals, "rgb|rgba")
s = "this ain't right"
err = validator.ValidateFieldByTag(s, "rgb|rgba|len=10")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "rgb|rgba|len")
c.Assert(err.ErrorTag, Equals, "rgb|rgba|len")
s = "this is right"
err = validator.ValidateFieldByTag(s, "rgb|rgba|len=13")
@ -272,27 +272,27 @@ func (ms *MySuite) TestHsla(c *C) {
s = "hsl(361,100%,50%,1)"
err = validator.ValidateFieldByTag(s, "hsla")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "hsla")
c.Assert(err.ErrorTag, Equals, "hsla")
s = "hsl(361,100%,50%)"
err = validator.ValidateFieldByTag(s, "hsla")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "hsla")
c.Assert(err.ErrorTag, Equals, "hsla")
s = "hsla(361,100%,50%)"
err = validator.ValidateFieldByTag(s, "hsla")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "hsla")
c.Assert(err.ErrorTag, Equals, "hsla")
s = "hsla(360,101%,50%)"
err = validator.ValidateFieldByTag(s, "hsla")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "hsla")
c.Assert(err.ErrorTag, Equals, "hsla")
s = "hsla(360,100%,101%)"
err = validator.ValidateFieldByTag(s, "hsla")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "hsla")
c.Assert(err.ErrorTag, Equals, "hsla")
}
func (ms *MySuite) TestHsl(c *C) {
@ -308,22 +308,22 @@ func (ms *MySuite) TestHsl(c *C) {
s = "hsl(361,100%,50%)"
err = validator.ValidateFieldByTag(s, "hsl")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "hsl")
c.Assert(err.ErrorTag, Equals, "hsl")
s = "hsl(361,101%,50%)"
err = validator.ValidateFieldByTag(s, "hsl")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "hsl")
c.Assert(err.ErrorTag, Equals, "hsl")
s = "hsl(361,100%,101%)"
err = validator.ValidateFieldByTag(s, "hsl")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "hsl")
c.Assert(err.ErrorTag, Equals, "hsl")
s = "hsl(-10,100%,100%)"
err = validator.ValidateFieldByTag(s, "hsl")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "hsl")
c.Assert(err.ErrorTag, Equals, "hsl")
}
func (ms *MySuite) TestRgba(c *C) {
@ -343,17 +343,17 @@ func (ms *MySuite) TestRgba(c *C) {
s = "rgb(0, 31, 255)"
err = validator.ValidateFieldByTag(s, "rgba")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "rgba")
c.Assert(err.ErrorTag, Equals, "rgba")
s = "rgb(1,349,275,0.5)"
err = validator.ValidateFieldByTag(s, "rgba")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "rgba")
c.Assert(err.ErrorTag, Equals, "rgba")
s = "rgb(01,31,255,0.5)"
err = validator.ValidateFieldByTag(s, "rgba")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "rgba")
c.Assert(err.ErrorTag, Equals, "rgba")
}
func (ms *MySuite) TestRgb(c *C) {
@ -369,17 +369,17 @@ func (ms *MySuite) TestRgb(c *C) {
s = "rgb(1,349,275)"
err = validator.ValidateFieldByTag(s, "rgb")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "rgb")
c.Assert(err.ErrorTag, Equals, "rgb")
s = "rgb(01,31,255)"
err = validator.ValidateFieldByTag(s, "rgb")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "rgb")
c.Assert(err.ErrorTag, Equals, "rgb")
s = "rgba(0,31,255)"
err = validator.ValidateFieldByTag(s, "rgb")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "rgb")
c.Assert(err.ErrorTag, Equals, "rgb")
}
func (ms *MySuite) TestEmail(c *C) {
@ -390,19 +390,23 @@ func (ms *MySuite) TestEmail(c *C) {
s = ""
err = validator.ValidateFieldByTag(s, "email")
c.Assert(err.Error(), Equals, "email")
c.Assert(err, NotNil)
c.Assert(err.ErrorTag, Equals, "email")
s = "test@email"
err = validator.ValidateFieldByTag(s, "email")
c.Assert(err.Error(), Equals, "email")
c.Assert(err, NotNil)
c.Assert(err.ErrorTag, Equals, "email")
s = "test@email."
err = validator.ValidateFieldByTag(s, "email")
c.Assert(err.Error(), Equals, "email")
c.Assert(err, NotNil)
c.Assert(err.ErrorTag, Equals, "email")
s = "@email.com"
err = validator.ValidateFieldByTag(s, "email")
c.Assert(err.Error(), Equals, "email")
c.Assert(err, NotNil)
c.Assert(err.ErrorTag, Equals, "email")
}
func (ms *MySuite) TestHexColor(c *C) {
@ -417,11 +421,13 @@ func (ms *MySuite) TestHexColor(c *C) {
s = "fff"
err = validator.ValidateFieldByTag(s, "hexcolor")
c.Assert(err.Error(), Equals, "hexcolor")
c.Assert(err, NotNil)
c.Assert(err.ErrorTag, Equals, "hexcolor")
s = "fffFF"
err = validator.ValidateFieldByTag(s, "hexcolor")
c.Assert(err.Error(), Equals, "hexcolor")
c.Assert(err, NotNil)
c.Assert(err.ErrorTag, Equals, "hexcolor")
}
func (ms *MySuite) TestHexadecimal(c *C) {
@ -432,7 +438,8 @@ func (ms *MySuite) TestHexadecimal(c *C) {
s = "abcdefg"
err = validator.ValidateFieldByTag(s, "hexadecimal")
c.Assert(err.Error(), Equals, "hexadecimal")
c.Assert(err, NotNil)
c.Assert(err.ErrorTag, Equals, "hexadecimal")
}
func (ms *MySuite) TestNumber(c *C) {
@ -443,31 +450,38 @@ func (ms *MySuite) TestNumber(c *C) {
s = "+1"
err = validator.ValidateFieldByTag(s, "number")
c.Assert(err.Error(), Equals, "number")
c.Assert(err, NotNil)
c.Assert(err.ErrorTag, Equals, "number")
s = "-1"
err = validator.ValidateFieldByTag(s, "number")
c.Assert(err.Error(), Equals, "number")
c.Assert(err, NotNil)
c.Assert(err.ErrorTag, Equals, "number")
s = "1.12"
err = validator.ValidateFieldByTag(s, "number")
c.Assert(err.Error(), Equals, "number")
c.Assert(err, NotNil)
c.Assert(err.ErrorTag, Equals, "number")
s = "+1.12"
err = validator.ValidateFieldByTag(s, "number")
c.Assert(err.Error(), Equals, "number")
c.Assert(err, NotNil)
c.Assert(err.ErrorTag, Equals, "number")
s = "-1.12"
err = validator.ValidateFieldByTag(s, "number")
c.Assert(err.Error(), Equals, "number")
c.Assert(err, NotNil)
c.Assert(err.ErrorTag, Equals, "number")
s = "1."
err = validator.ValidateFieldByTag(s, "number")
c.Assert(err.Error(), Equals, "number")
c.Assert(err, NotNil)
c.Assert(err.ErrorTag, Equals, "number")
s = "1.o"
err = validator.ValidateFieldByTag(s, "number")
c.Assert(err.Error(), Equals, "number")
c.Assert(err, NotNil)
c.Assert(err.ErrorTag, Equals, "number")
}
func (ms *MySuite) TestNumeric(c *C) {
@ -498,11 +512,13 @@ func (ms *MySuite) TestNumeric(c *C) {
s = "1."
err = validator.ValidateFieldByTag(s, "numeric")
c.Assert(err.Error(), Equals, "numeric")
c.Assert(err, NotNil)
c.Assert(err.ErrorTag, Equals, "numeric")
s = "1.o"
err = validator.ValidateFieldByTag(s, "numeric")
c.Assert(err.Error(), Equals, "numeric")
c.Assert(err, NotNil)
c.Assert(err.ErrorTag, Equals, "numeric")
}
func (ms *MySuite) TestAlphaNumeric(c *C) {
@ -513,7 +529,8 @@ func (ms *MySuite) TestAlphaNumeric(c *C) {
s = "abc!23"
err = validator.ValidateFieldByTag(s, "alphanum")
c.Assert(err.Error(), Equals, "alphanum")
c.Assert(err, NotNil)
c.Assert(err.ErrorTag, Equals, "alphanum")
c.Assert(func() { validator.ValidateFieldByTag(1, "alphanum") }, PanicMatches, "Bad field type int")
}
@ -526,7 +543,8 @@ func (ms *MySuite) TestAlpha(c *C) {
s = "abc1"
err = validator.ValidateFieldByTag(s, "alpha")
c.Assert(err.Error(), Equals, "alpha")
c.Assert(err, NotNil)
c.Assert(err.ErrorTag, Equals, "alpha")
c.Assert(func() { validator.ValidateFieldByTag(1, "alpha") }, PanicMatches, "Bad field type int")
}

Loading…
Cancel
Save