diff --git a/doc.go b/doc.go index dac6b23..59fdbd0 100644 --- a/doc.go +++ b/doc.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" { diff --git a/validator.go b/validator.go index 53cc651..4ffea06 100644 --- a/validator.go +++ b/validator.go @@ -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 } diff --git a/validator_test.go b/validator_test.go index 685cc57..2f73b00 100644 --- a/validator_test.go +++ b/validator_test.go @@ -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") }