Skip to content

Commit ac82433

Browse files
Dean KarnDean Karn
authored andcommitted
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.
1 parent 550287f commit ac82433

File tree

3 files changed

+87
-97
lines changed

3 files changed

+87
-97
lines changed

doc.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ but you may also create a new instance if needed.
88
99
// built in
1010
errs := validator.ValidateStruct(//your struct)
11-
errs := validator.ValidateFieldByTag(field, "omitempty,min=1,max=10")
11+
valErr := validator.ValidateFieldByTag(field, "omitempty,min=1,max=10")
1212
1313
// new
1414
newValidator = validator.New("struct tag name", validator.BakedInFunctions)
@@ -57,7 +57,7 @@ intended use is for development + debugging, not a production error message.
5757
5858
Why not a better error message? because this library intends for you to handle your own error messages
5959
60-
Why should I handle my own errors? Many reasons, for me building and internationalized application
60+
Why should I handle my own errors? Many reasons, for me building an internationalized application
6161
I needed to know the field and what validation failed so that I could provide an error in the users specific language.
6262
6363
if fieldErr.Field == "Name" {

validator.go

Lines changed: 30 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ const (
2727
type FieldValidationError struct {
2828
Field string
2929
ErrorTag string
30+
Kind reflect.Kind
31+
Param string
32+
Value interface{}
3033
}
3134

3235
// 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 {
220223

221224
default:
222225

223-
if fieldError := v.validateStructFieldByTag(valueField.Interface(), typeField.Name, tag); fieldError != nil {
226+
if fieldError := v.validateFieldByNameAndTag(valueField.Interface(), typeField.Name, tag); fieldError != nil {
224227
validationErrors.Errors[fieldError.Field] = fieldError
225228
// free up memory reference
226229
fieldError = nil
@@ -235,32 +238,19 @@ func (v *Validator) ValidateStruct(s interface{}) *StructValidationErrors {
235238
return validationErrors
236239
}
237240

238-
// ValidateFieldWithTag validates the given field by the given tag arguments
239-
func (v *Validator) validateStructFieldByTag(f interface{}, name string, tag string) *FieldValidationError {
240-
241-
if err := v.validateFieldByNameAndTag(f, name, tag); err != nil {
242-
return &FieldValidationError{
243-
Field: name,
244-
ErrorTag: err.Error(),
245-
}
246-
}
247-
248-
return nil
249-
}
250-
251241
// ValidateFieldByTag allows validation of a single field with the internal validator, still using tag style validation to check multiple errors
252-
func ValidateFieldByTag(f interface{}, tag string) error {
242+
func ValidateFieldByTag(f interface{}, tag string) *FieldValidationError {
253243

254244
return internalValidator.validateFieldByNameAndTag(f, "", tag)
255245
}
256246

257247
// ValidateFieldByTag allows validation of a single field, still using tag style validation to check multiple errors
258-
func (v *Validator) ValidateFieldByTag(f interface{}, tag string) error {
248+
func (v *Validator) ValidateFieldByTag(f interface{}, tag string) *FieldValidationError {
259249

260250
return v.validateFieldByNameAndTag(f, "", tag)
261251
}
262252

263-
func (v *Validator) validateFieldByNameAndTag(f interface{}, name string, tag string) error {
253+
func (v *Validator) validateFieldByNameAndTag(f interface{}, name string, tag string) *FieldValidationError {
264254

265255
// This is a double check if coming from ValidateStruct but need to be here in case function is called directly
266256
if tag == "-" {
@@ -283,7 +273,8 @@ func (v *Validator) validateFieldByNameAndTag(f interface{}, name string, tag st
283273
panic("Invalid field passed to ValidateFieldWithTag")
284274
}
285275

286-
// TODO: validate commas in regex's
276+
var valErr *FieldValidationError
277+
var err error
287278
valTags := strings.Split(tag, ",")
288279

289280
for _, valTag := range valTags {
@@ -296,62 +287,35 @@ func (v *Validator) validateFieldByNameAndTag(f interface{}, name string, tag st
296287

297288
for _, val := range orVals {
298289

299-
key, err := v.validateFieldByNameAndSingleTag(f, name, val)
290+
valErr, err = v.validateFieldByNameAndSingleTag(f, name, val)
300291

301292
if err == nil {
302293
return nil
303294
}
304295

305-
errTag += "|" + key
296+
errTag += "|" + valErr.ErrorTag
306297

307298
}
308299

309300
errTag = strings.TrimLeft(errTag, "|")
310301

311-
return errors.New(errTag)
312-
}
302+
valErr.ErrorTag = errTag
303+
valErr.Kind = valueField.Kind()
313304

314-
if _, err := v.validateFieldByNameAndSingleTag(f, name, valTag); err != nil {
315-
return err
305+
return valErr
316306
}
317307

318-
// TODO: validate = in regex's
319-
// vals := strings.Split(valTag, "=")
320-
// key := strings.Trim(vals[0], " ")
321-
//
322-
// if len(key) == 0 {
323-
// panic(fmt.Sprintf("Invalid validation tag on field %s", name))
324-
// }
325-
//
326-
// // OK to continue because we checked it's existance before getting into this loop
327-
// if key == omitempty {
328-
// continue
329-
// }
330-
//
331-
// valFunc, ok := v.validationFuncs[key]
332-
// if !ok {
333-
// panic(fmt.Sprintf("Undefined validation function on field %s", name))
334-
// }
335-
//
336-
// param := ""
337-
// if len(vals) > 1 {
338-
// param = strings.Trim(vals[1], " ")
339-
// }
340-
//
341-
// if err := valFunc(f, param); !err {
342-
//
343-
// return errors.New(key)
344-
// }
345-
// if err := v.validateFieldByNameAndSingleTag(f, name, valTag); err != nil {
346-
// return err
347-
// }
308+
if valErr, err = v.validateFieldByNameAndSingleTag(f, name, valTag); err != nil {
309+
valErr.Kind = valueField.Kind()
348310

311+
return valErr
312+
}
349313
}
350314

351315
return nil
352316
}
353317

354-
func (v *Validator) validateFieldByNameAndSingleTag(f interface{}, name string, valTag string) (string, error) {
318+
func (v *Validator) validateFieldByNameAndSingleTag(f interface{}, name string, valTag string) (*FieldValidationError, error) {
355319

356320
vals := strings.Split(valTag, "=")
357321
key := strings.Trim(vals[0], " ")
@@ -360,9 +324,16 @@ func (v *Validator) validateFieldByNameAndSingleTag(f interface{}, name string,
360324
panic(fmt.Sprintf("Invalid validation tag on field %s", name))
361325
}
362326

327+
valErr := &FieldValidationError{
328+
Field: name,
329+
ErrorTag: key,
330+
Value: f,
331+
Param: "",
332+
}
333+
363334
// OK to continue because we checked it's existance before getting into this loop
364335
if key == omitempty {
365-
return key, nil
336+
return valErr, nil
366337
}
367338

368339
valFunc, ok := v.validationFuncs[key]
@@ -376,8 +347,9 @@ func (v *Validator) validateFieldByNameAndSingleTag(f interface{}, name string,
376347
}
377348

378349
if err := valFunc(f, param); !err {
379-
return key, errors.New(key)
350+
valErr.Param = param
351+
return valErr, errors.New(key)
380352
}
381353

382-
return key, nil
354+
return valErr, nil
383355
}

0 commit comments

Comments
 (0)