123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- package validator
- import (
- "bytes"
- "fmt"
- "reflect"
- "strings"
- ut "github.com/go-playground/universal-translator"
- )
- const (
- fieldErrMsg = "Key: '%s' Error:Field validation for '%s' failed on the '%s' tag"
- )
- // ValidationErrorsTranslations is the translation return type
- type ValidationErrorsTranslations map[string]string
- // InvalidValidationError describes an invalid argument passed to
- // `Struct`, `StructExcept`, StructPartial` or `Field`
- type InvalidValidationError struct {
- Type reflect.Type
- }
- // Error returns InvalidValidationError message
- func (e *InvalidValidationError) Error() string {
- if e.Type == nil {
- return "validator: (nil)"
- }
- return "validator: (nil " + e.Type.String() + ")"
- }
- // ValidationErrors is an array of FieldError's
- // for use in custom error messages post validation.
- type ValidationErrors []FieldError
- // Error is intended for use in development + debugging and not intended to be a production error message.
- // It allows ValidationErrors to subscribe to the Error interface.
- // All information to create an error message specific to your application is contained within
- // the FieldError found within the ValidationErrors array
- func (ve ValidationErrors) Error() string {
- buff := bytes.NewBufferString("")
- var fe *fieldError
- for i := 0; i < len(ve); i++ {
- fe = ve[i].(*fieldError)
- buff.WriteString(fe.Error())
- buff.WriteString("\n")
- }
- return strings.TrimSpace(buff.String())
- }
- // Translate translates all of the ValidationErrors
- func (ve ValidationErrors) Translate(ut ut.Translator) ValidationErrorsTranslations {
- trans := make(ValidationErrorsTranslations)
- var fe *fieldError
- for i := 0; i < len(ve); i++ {
- fe = ve[i].(*fieldError)
- // // in case an Anonymous struct was used, ensure that the key
- // // would be 'Username' instead of ".Username"
- // if len(fe.ns) > 0 && fe.ns[:1] == "." {
- // trans[fe.ns[1:]] = fe.Translate(ut)
- // continue
- // }
- trans[fe.ns] = fe.Translate(ut)
- }
- return trans
- }
- // FieldError contains all functions to get error details
- type FieldError interface {
- // returns the validation tag that failed. if the
- // validation was an alias, this will return the
- // alias name and not the underlying tag that failed.
- //
- // eg. alias "iscolor": "hexcolor|rgb|rgba|hsl|hsla"
- // will return "iscolor"
- Tag() string
- // returns the validation tag that failed, even if an
- // alias the actual tag within the alias will be returned.
- // If an 'or' validation fails the entire or will be returned.
- //
- // eg. alias "iscolor": "hexcolor|rgb|rgba|hsl|hsla"
- // will return "hexcolor|rgb|rgba|hsl|hsla"
- ActualTag() string
- // returns the namespace for the field error, with the tag
- // name taking precedence over the fields actual name.
- //
- // eg. JSON name "User.fname"
- //
- // See StructNamespace() for a version that returns actual names.
- //
- // NOTE: this field can be blank when validating a single primitive field
- // using validate.Field(...) as there is no way to extract it's name
- Namespace() string
- // returns the namespace for the field error, with the fields
- // actual name.
- //
- // eq. "User.FirstName" see Namespace for comparison
- //
- // NOTE: this field can be blank when validating a single primitive field
- // using validate.Field(...) as there is no way to extract it's name
- StructNamespace() string
- // returns the fields name with the tag name taking precedence over the
- // fields actual name.
- //
- // eq. JSON name "fname"
- // see StructField for comparison
- Field() string
- // returns the fields actual name from the struct, when able to determine.
- //
- // eq. "FirstName"
- // see Field for comparison
- StructField() string
- // returns the actual fields value in case needed for creating the error
- // message
- Value() interface{}
- // returns the param value, in string form for comparison; this will also
- // help with generating an error message
- Param() string
- // Kind returns the Field's reflect Kind
- //
- // eg. time.Time's kind is a struct
- Kind() reflect.Kind
- // Type returns the Field's reflect Type
- //
- // // eg. time.Time's type is time.Time
- Type() reflect.Type
- // returns the FieldError's translated error
- // from the provided 'ut.Translator' and registered 'TranslationFunc'
- //
- // NOTE: if no registered translator can be found it returns the same as
- // calling fe.Error()
- Translate(ut ut.Translator) string
- }
- // compile time interface checks
- var _ FieldError = new(fieldError)
- var _ error = new(fieldError)
- // fieldError contains a single field's validation error along
- // with other properties that may be needed for error message creation
- // it complies with the FieldError interface
- type fieldError struct {
- v *Validate
- tag string
- actualTag string
- ns string
- structNs string
- fieldLen uint8
- structfieldLen uint8
- value interface{}
- param string
- kind reflect.Kind
- typ reflect.Type
- }
- // Tag returns the validation tag that failed.
- func (fe *fieldError) Tag() string {
- return fe.tag
- }
- // ActualTag returns the validation tag that failed, even if an
- // alias the actual tag within the alias will be returned.
- func (fe *fieldError) ActualTag() string {
- return fe.actualTag
- }
- // Namespace returns the namespace for the field error, with the tag
- // name taking precedence over the fields actual name.
- func (fe *fieldError) Namespace() string {
- return fe.ns
- }
- // StructNamespace returns the namespace for the field error, with the fields
- // actual name.
- func (fe *fieldError) StructNamespace() string {
- return fe.structNs
- }
- // Field returns the fields name with the tag name taking precedence over the
- // fields actual name.
- func (fe *fieldError) Field() string {
- return fe.ns[len(fe.ns)-int(fe.fieldLen):]
- // // return fe.field
- // fld := fe.ns[len(fe.ns)-int(fe.fieldLen):]
- // log.Println("FLD:", fld)
- // if len(fld) > 0 && fld[:1] == "." {
- // return fld[1:]
- // }
- // return fld
- }
- // returns the fields actual name from the struct, when able to determine.
- func (fe *fieldError) StructField() string {
- // return fe.structField
- return fe.structNs[len(fe.structNs)-int(fe.structfieldLen):]
- }
- // Value returns the actual fields value in case needed for creating the error
- // message
- func (fe *fieldError) Value() interface{} {
- return fe.value
- }
- // Param returns the param value, in string form for comparison; this will
- // also help with generating an error message
- func (fe *fieldError) Param() string {
- return fe.param
- }
- // Kind returns the Field's reflect Kind
- func (fe *fieldError) Kind() reflect.Kind {
- return fe.kind
- }
- // Type returns the Field's reflect Type
- func (fe *fieldError) Type() reflect.Type {
- return fe.typ
- }
- // Error returns the fieldError's error message
- func (fe *fieldError) Error() string {
- return fmt.Sprintf(fieldErrMsg, fe.ns, fe.Field(), fe.tag)
- }
- // Translate returns the FieldError's translated error
- // from the provided 'ut.Translator' and registered 'TranslationFunc'
- //
- // NOTE: is not registered translation can be found it returns the same
- // as calling fe.Error()
- func (fe *fieldError) Translate(ut ut.Translator) string {
- m, ok := fe.v.transTagFunc[ut]
- if !ok {
- return fe.Error()
- }
- fn, ok := m[fe.tag]
- if !ok {
- return fe.Error()
- }
- return fn(ut, fe)
- }
|