errors.go (7433B)
1 package validator 2 3 import ( 4 "bytes" 5 "fmt" 6 "reflect" 7 "strings" 8 9 ut "github.com/go-playground/universal-translator" 10 ) 11 12 const ( 13 fieldErrMsg = "Key: '%s' Error:Field validation for '%s' failed on the '%s' tag" 14 ) 15 16 // ValidationErrorsTranslations is the translation return type 17 type ValidationErrorsTranslations map[string]string 18 19 // InvalidValidationError describes an invalid argument passed to 20 // `Struct`, `StructExcept`, StructPartial` or `Field` 21 type InvalidValidationError struct { 22 Type reflect.Type 23 } 24 25 // Error returns InvalidValidationError message 26 func (e *InvalidValidationError) Error() string { 27 28 if e.Type == nil { 29 return "validator: (nil)" 30 } 31 32 return "validator: (nil " + e.Type.String() + ")" 33 } 34 35 // ValidationErrors is an array of FieldError's 36 // for use in custom error messages post validation. 37 type ValidationErrors []FieldError 38 39 // Error is intended for use in development + debugging and not intended to be a production error message. 40 // It allows ValidationErrors to subscribe to the Error interface. 41 // All information to create an error message specific to your application is contained within 42 // the FieldError found within the ValidationErrors array 43 func (ve ValidationErrors) Error() string { 44 45 buff := bytes.NewBufferString("") 46 47 for i := 0; i < len(ve); i++ { 48 49 buff.WriteString(ve[i].Error()) 50 buff.WriteString("\n") 51 } 52 53 return strings.TrimSpace(buff.String()) 54 } 55 56 // Translate translates all of the ValidationErrors 57 func (ve ValidationErrors) Translate(ut ut.Translator) ValidationErrorsTranslations { 58 59 trans := make(ValidationErrorsTranslations) 60 61 var fe *fieldError 62 63 for i := 0; i < len(ve); i++ { 64 fe = ve[i].(*fieldError) 65 66 // // in case an Anonymous struct was used, ensure that the key 67 // // would be 'Username' instead of ".Username" 68 // if len(fe.ns) > 0 && fe.ns[:1] == "." { 69 // trans[fe.ns[1:]] = fe.Translate(ut) 70 // continue 71 // } 72 73 trans[fe.ns] = fe.Translate(ut) 74 } 75 76 return trans 77 } 78 79 // FieldError contains all functions to get error details 80 type FieldError interface { 81 82 // Tag returns the validation tag that failed. if the 83 // validation was an alias, this will return the 84 // alias name and not the underlying tag that failed. 85 // 86 // eg. alias "iscolor": "hexcolor|rgb|rgba|hsl|hsla" 87 // will return "iscolor" 88 Tag() string 89 90 // ActualTag returns the validation tag that failed, even if an 91 // alias the actual tag within the alias will be returned. 92 // If an 'or' validation fails the entire or will be returned. 93 // 94 // eg. alias "iscolor": "hexcolor|rgb|rgba|hsl|hsla" 95 // will return "hexcolor|rgb|rgba|hsl|hsla" 96 ActualTag() string 97 98 // Namespace returns the namespace for the field error, with the tag 99 // name taking precedence over the field's actual name. 100 // 101 // eg. JSON name "User.fname" 102 // 103 // See StructNamespace() for a version that returns actual names. 104 // 105 // NOTE: this field can be blank when validating a single primitive field 106 // using validate.Field(...) as there is no way to extract it's name 107 Namespace() string 108 109 // StructNamespace returns the namespace for the field error, with the field's 110 // actual name. 111 // 112 // eq. "User.FirstName" see Namespace for comparison 113 // 114 // NOTE: this field can be blank when validating a single primitive field 115 // using validate.Field(...) as there is no way to extract its name 116 StructNamespace() string 117 118 // Field returns the fields name with the tag name taking precedence over the 119 // field's actual name. 120 // 121 // eq. JSON name "fname" 122 // see StructField for comparison 123 Field() string 124 125 // StructField returns the field's actual name from the struct, when able to determine. 126 // 127 // eq. "FirstName" 128 // see Field for comparison 129 StructField() string 130 131 // Value returns the actual field's value in case needed for creating the error 132 // message 133 Value() interface{} 134 135 // Param returns the param value, in string form for comparison; this will also 136 // help with generating an error message 137 Param() string 138 139 // Kind returns the Field's reflect Kind 140 // 141 // eg. time.Time's kind is a struct 142 Kind() reflect.Kind 143 144 // Type returns the Field's reflect Type 145 // 146 // eg. time.Time's type is time.Time 147 Type() reflect.Type 148 149 // Translate returns the FieldError's translated error 150 // from the provided 'ut.Translator' and registered 'TranslationFunc' 151 // 152 // NOTE: if no registered translator can be found it returns the same as 153 // calling fe.Error() 154 Translate(ut ut.Translator) string 155 156 // Error returns the FieldError's message 157 Error() string 158 } 159 160 // compile time interface checks 161 var _ FieldError = new(fieldError) 162 var _ error = new(fieldError) 163 164 // fieldError contains a single field's validation error along 165 // with other properties that may be needed for error message creation 166 // it complies with the FieldError interface 167 type fieldError struct { 168 v *Validate 169 tag string 170 actualTag string 171 ns string 172 structNs string 173 fieldLen uint8 174 structfieldLen uint8 175 value interface{} 176 param string 177 kind reflect.Kind 178 typ reflect.Type 179 } 180 181 // Tag returns the validation tag that failed. 182 func (fe *fieldError) Tag() string { 183 return fe.tag 184 } 185 186 // ActualTag returns the validation tag that failed, even if an 187 // alias the actual tag within the alias will be returned. 188 func (fe *fieldError) ActualTag() string { 189 return fe.actualTag 190 } 191 192 // Namespace returns the namespace for the field error, with the tag 193 // name taking precedence over the field's actual name. 194 func (fe *fieldError) Namespace() string { 195 return fe.ns 196 } 197 198 // StructNamespace returns the namespace for the field error, with the field's 199 // actual name. 200 func (fe *fieldError) StructNamespace() string { 201 return fe.structNs 202 } 203 204 // Field returns the field's name with the tag name taking precedence over the 205 // field's actual name. 206 func (fe *fieldError) Field() string { 207 208 return fe.ns[len(fe.ns)-int(fe.fieldLen):] 209 // // return fe.field 210 // fld := fe.ns[len(fe.ns)-int(fe.fieldLen):] 211 212 // log.Println("FLD:", fld) 213 214 // if len(fld) > 0 && fld[:1] == "." { 215 // return fld[1:] 216 // } 217 218 // return fld 219 } 220 221 // StructField returns the field's actual name from the struct, when able to determine. 222 func (fe *fieldError) StructField() string { 223 // return fe.structField 224 return fe.structNs[len(fe.structNs)-int(fe.structfieldLen):] 225 } 226 227 // Value returns the actual field's value in case needed for creating the error 228 // message 229 func (fe *fieldError) Value() interface{} { 230 return fe.value 231 } 232 233 // Param returns the param value, in string form for comparison; this will 234 // also help with generating an error message 235 func (fe *fieldError) Param() string { 236 return fe.param 237 } 238 239 // Kind returns the Field's reflect Kind 240 func (fe *fieldError) Kind() reflect.Kind { 241 return fe.kind 242 } 243 244 // Type returns the Field's reflect Type 245 func (fe *fieldError) Type() reflect.Type { 246 return fe.typ 247 } 248 249 // Error returns the fieldError's error message 250 func (fe *fieldError) Error() string { 251 return fmt.Sprintf(fieldErrMsg, fe.ns, fe.Field(), fe.tag) 252 } 253 254 // Translate returns the FieldError's translated error 255 // from the provided 'ut.Translator' and registered 'TranslationFunc' 256 // 257 // NOTE: if no registered translation can be found, it returns the original 258 // untranslated error message. 259 func (fe *fieldError) Translate(ut ut.Translator) string { 260 261 m, ok := fe.v.transTagFunc[ut] 262 if !ok { 263 return fe.Error() 264 } 265 266 fn, ok := m[fe.tag] 267 if !ok { 268 return fe.Error() 269 } 270 271 return fn(ut, fe) 272 }