github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/services/validators/validator.go (about) 1 /* 2 * Copyright 2023 Wang Min Xiang 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package validators 19 20 import ( 21 se "errors" 22 "fmt" 23 "github.com/aacfactory/errors" 24 "github.com/go-playground/validator/v10" 25 "reflect" 26 "strings" 27 ) 28 29 type ValidateRegister func(validate *validator.Validate) *validator.Validate 30 31 func AddValidateRegister(register ValidateRegister) { 32 _validator.validate = register(_validator.validate) 33 } 34 35 var _validator *validate = nil 36 37 func ValidateWithErrorTitle(value interface{}, title string) (err errors.CodeError) { 38 err = _validator.Validate(value, title) 39 return 40 } 41 42 // Validate 43 // field tag is validate 44 // message tag is validate-message or message 45 func Validate(value interface{}) (err errors.CodeError) { 46 err = ValidateWithErrorTitle(value, "invalid") 47 return 48 } 49 50 type Validator interface { 51 Validate(v interface{}) (err errors.CodeError) 52 } 53 54 type validate struct { 55 validate *validator.Validate 56 } 57 58 func (v *validate) Validate(value interface{}, title string) (err errors.CodeError) { 59 validateErr := v.validate.Struct(value) 60 if validateErr == nil { 61 return 62 } 63 var validationErrors validator.ValidationErrors 64 ok := se.As(validateErr, &validationErrors) 65 if !ok { 66 err = errors.Warning(fmt.Sprintf("fns: validate value failed")).WithCause(validateErr) 67 return 68 } 69 err = errors.BadRequest(title) 70 for _, validationError := range validationErrors { 71 sf := validationError.Namespace() 72 idx := strings.Index(sf, ".") 73 if idx < 0 { 74 continue 75 } 76 exp := sf[idx+1:] 77 key, message := validateFieldMessage(reflect.TypeOf(value), exp) 78 if key == "" { 79 err = errors.Warning(fmt.Sprintf("fns: validate value failed for json tag of %s was not founed", sf)) 80 return 81 } 82 if message == "" { 83 err = errors.Warning(fmt.Sprintf("fns: validate value failed for message tag of %s was not founed", sf)) 84 return 85 } 86 err = err.WithMeta(key, message) 87 } 88 return 89 } 90 91 func validateFieldMessage(_type reflect.Type, exp string) (key string, msg string) { 92 if _type.Kind() == reflect.Ptr { 93 _type = _type.Elem() 94 } 95 fieldName := "" 96 idx := strings.Index(exp, ".") 97 if idx > 0 { 98 fieldName = exp[0:idx] 99 } else { 100 fieldName = exp 101 } 102 field, has := _type.FieldByName(fieldName) 103 if !has { 104 return 105 } 106 xk := field.Tag.Get("json") 107 if pos := strings.Index(xk, ","); pos > 0 { 108 xk = xk[0:pos] 109 } 110 111 if idx > 0 { 112 key, msg = validateFieldMessage(field.Type, exp[idx+1:]) 113 key = xk + "." + key 114 return 115 } 116 key = xk 117 msg, has = field.Tag.Lookup("validate-message") 118 if !has { 119 msg = field.Tag.Get("message") 120 } 121 return 122 }