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  }