validator

package
v1.21.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 9, 2021 License: MIT Imports: 20 Imported by: 0

Documentation

Overview

Each Validator have at least two process methods, one for 'Parsing' and one for 'Validating'.

In 'Parsing' stage, we call validator as 'ValidatorCreator', and it will be register to some 'ValidatorMgr' for caching.

Parsing

There are common 'Rule DSL' below:

// simple
@name

// with parameters
@name<param1>
@name<param1,param2>

// with ranges
@name[from, to)
@name[length]

// with values
@name{VALUE1,VALUE2,VALUE3}
@name{%v}

// with regexp
@name/\d+/

// optional and default value
@name?
@name = value
@name = 'some string value'

// composes
@map<@string[1,10],@string{A,B,C}>
@map<@string[1,10],@string/\d+/>[0,10]

Then the parsed rule will be transform to special validators:

Validating

We can create validator by 'Rule DSL', and also can configure them by validator struct field as conditions. Then call the method `Validate(v interface{}) error` to do value validations.

Index

Examples

Constants

View Source
const (
	TagValidate = "validate"
	TagDefault  = "default"
	TagErrMsg   = "errMsg"
)

Variables

View Source
var (
	TargetFloatValue                = "float value"
	TargetDecimalDigitsOfFloatValue = "decimal digits of float value"
	TargetTotalDigitsOfFloatValue   = "total digits of float value"
)
View Source
var (
	TargetIntValue = "int value"
)
View Source
var (
	TargetMapLength = "map length"
)
View Source
var (
	TargetSliceLength = "slice length"
)
View Source
var (
	TargetStringLength = "string length"
)
View Source
var (
	TargetUintValue = "uint value"
)
View Source
var ValidatorMgrDefault = NewValidatorFactory()

Functions

func ContextWithNamedTagKey

func ContextWithNamedTagKey(ctx context.Context, namedTagKey string) context.Context

func ContextWithValidatorMgr

func ContextWithValidatorMgr(c context.Context, validatorMgr ValidatorMgr) context.Context

func MaxInt

func MaxInt(bitSize uint) int64

func MaxUint

func MaxUint(bitSize uint) uint64

func MinInt

func MinInt(bitSize uint) int64

func NamedKeyFromContext

func NamedKeyFromContext(ctx context.Context) string

func RangeFromUint

func RangeFromUint(min uint64, max *uint64) []*rules.RuleLit

func ToMarshalledText

func ToMarshalledText(v interface{}) string

func UintRange

func UintRange(typ string, bitSize uint, ranges ...*rules.RuleLit) (uint64, *uint64, error)

Types

type ErrorSet

type ErrorSet struct {
	// contains filtered or unexported fields
}
Example
subErrSet := NewErrorSet("")
subErrSet.AddErr(fmt.Errorf("err"), "PropA")
subErrSet.AddErr(fmt.Errorf("err"), "PropB")

errSet := NewErrorSet("")
errSet.AddErr(fmt.Errorf("err"), "Key")
errSet.AddErr(subErrSet.Err(), "Key", 1)
errSet.AddErr(NewErrorSet("").Err(), "Key", 1)

fmt.Println(errSet.Flatten().Len())
fmt.Println(errSet)
Output:

3
Key err
Key[1].PropA err
Key[1].PropB err

func NewErrorSet

func NewErrorSet(paths ...interface{}) *ErrorSet

func (*ErrorSet) AddErr

func (es *ErrorSet) AddErr(err error, keyPathNodes ...interface{})

func (*ErrorSet) Each

func (es *ErrorSet) Each(cb func(fieldErr *FieldError))

func (*ErrorSet) Err

func (es *ErrorSet) Err() error

func (*ErrorSet) Error

func (es *ErrorSet) Error() string

func (*ErrorSet) Flatten

func (es *ErrorSet) Flatten() *ErrorSet

func (*ErrorSet) Len

func (es *ErrorSet) Len() int

func (*ErrorSet) ToErrorFields added in v1.21.1

func (es *ErrorSet) ToErrorFields() statuserror.ErrorFields

type FieldError

type FieldError struct {
	Path  KeyPath
	Error error
}

type FloatValidator

type FloatValidator struct {
	MaxDigits     uint
	DecimalDigits *uint

	Minimum          *float64
	Maximum          *float64
	ExclusiveMaximum bool
	ExclusiveMinimum bool

	MultipleOf float64
	Enums      []float64
}

Validator for float32 and float64

Rules:

ranges

@float[min,max]
@float[1,10] // value should large or equal than 1 and less or equal than 10
@float(1,10] // value should large than 1 and less or equal than 10
@float[1,10) // value should large or equal than 1

@float[1,)  // value should large or equal than 1
@float[,1)  // value should less than 1

enumeration

@float{1.1,1.2,1.3} // value should be one of these

multiple of some float value

@float{%multipleOf}
@float{%2.2} // value should be multiple of 2.2

max digits and decimal digits. when defined, all values in rule should be under range of them.

@float<MAX_DIGITS,DECIMAL_DIGITS>
@float<5,2> // will checkout these values invalid: 1.111 (decimal digits too many), 12345.6 (digits too many)

composes

@float<MAX_DIGITS,DECIMAL_DIGITS>[min,max]

aliases:

@float32 = @float<7>
@float64 = @float<15>

func (FloatValidator) Names

func (FloatValidator) Names() []string

func (FloatValidator) New

func (FloatValidator) New(ctx context.Context, rule *Rule) (Validator, error)

func (*FloatValidator) SetDefaults

func (validator *FloatValidator) SetDefaults()

func (*FloatValidator) String

func (validator *FloatValidator) String() string

func (*FloatValidator) TypeCheck

func (validator *FloatValidator) TypeCheck(rule *Rule) error

func (*FloatValidator) Validate

func (validator *FloatValidator) Validate(v interface{}) error

type IntValidator

type IntValidator struct {
	BitSize uint

	Minimum          *int64
	Maximum          *int64
	MultipleOf       int64
	ExclusiveMaximum bool
	ExclusiveMinimum bool

	Enums []int64
}

Validator for int

Rules:

ranges

@int[min,max]
@int[1,10] // value should large or equal than 1 and less or equal than 10
@int(1,10] // value should large than 1 and less or equal than 10
@int[1,10) // value should large or equal than 1

@int[1,)  // value should large or equal than 1 and less than the maxinum of int32
@int[,1)  // value should less than 1 and large or equal than the mininum of int32
@int  // value should less or equal than maxinum of int32 and large or equal than the mininum of int32

enumeration

@int{1,2,3} // should one of these values

multiple of some int value

@int{%multipleOf}
@int{%2} // should be multiple of 2

bit size in parameter

@int<8>
@int<16>
@int<32>
@int<64>

composes

@int<8>[1,]

aliases:

@int8 = @int<8>
@int16 = @int<16>
@int32 = @int<32>
@int64 = @int<64>

Tips: for JavaScript https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MIN_SAFE_INTEGER

int<53>

func (IntValidator) Names

func (IntValidator) Names() []string

func (IntValidator) New

func (IntValidator) New(ctx context.Context, rule *Rule) (Validator, error)

func (*IntValidator) SetDefaults

func (validator *IntValidator) SetDefaults()

func (*IntValidator) String

func (validator *IntValidator) String() string

func (*IntValidator) TypeCheck

func (validator *IntValidator) TypeCheck(rule *Rule) error

func (*IntValidator) Validate

func (validator *IntValidator) Validate(v interface{}) error

type KeyPath

type KeyPath []interface{}

func (KeyPath) String

func (keyPath KeyPath) String() string

type Location

type Location string

type MapValidator

type MapValidator struct {
	MinProperties uint64
	MaxProperties *uint64

	KeyValidator  Validator
	ElemValidator Validator
}

Validator for map

Rules:

@map<KEY_RULE, ELEM_RULE>[minSize,maxSize]
@map<KEY_RULE, ELEM_RULE>[length]

@map<@string{A,B,C},@int[0]>[,100]

func (MapValidator) Names

func (MapValidator) Names() []string

func (*MapValidator) New

func (validator *MapValidator) New(ctx context.Context, rule *Rule) (Validator, error)

func (*MapValidator) String

func (validator *MapValidator) String() string

func (*MapValidator) Validate

func (validator *MapValidator) Validate(v interface{}) error

func (*MapValidator) ValidateReflectValue

func (validator *MapValidator) ValidateReflectValue(rv reflect.Value) error

type MissingRequired

type MissingRequired struct{}
Example
fmt.Println(MissingRequired{})
Output:

missing required field

func (MissingRequired) Error

func (MissingRequired) Error() string

type MultipleOfError

type MultipleOfError struct {
	Target     string
	Current    interface{}
	MultipleOf interface{}
}
Example
fmt.Println(&MultipleOfError{
	Target:     "int value",
	Current:    "11",
	MultipleOf: 2,
})
Output:

int value should be multiple of 2, but got invalid value 11

func (*MultipleOfError) Error

func (e *MultipleOfError) Error() string

type NotInEnumError

type NotInEnumError struct {
	Target  string
	Current interface{}
	Enums   []interface{}
}
Example
fmt.Println(&NotInEnumError{
	Target:  "int value",
	Current: "11",
	Enums: []interface{}{
		"1", "2", "3",
	},
})
Output:

int value should be one of 1, 2, 3, but got invalid value 11

func (*NotInEnumError) Error

func (e *NotInEnumError) Error() string

type NotMatchError

type NotMatchError struct {
	Target  string
	Current interface{}
	Pattern string
}
Example
fmt.Println(&NotMatchError{
	Target:  "number",
	Current: "1",
	Pattern: `/\d+/`,
})
Output:

number /\d+/ not match 1

func (*NotMatchError) Error

func (err *NotMatchError) Error() string

type OutOfRangeError

type OutOfRangeError struct {
	Target           string
	Current          interface{}
	Minimum          interface{}
	Maximum          interface{}
	ExclusiveMaximum bool
	ExclusiveMinimum bool
}
Example
fmt.Println(&OutOfRangeError{
	Target:           "int value",
	Minimum:          "1",
	Maximum:          "10",
	Current:          "11",
	ExclusiveMinimum: true,
	ExclusiveMaximum: true,
})
Output:

int value should be larger or equal than 1 and less or equal than 10, but got invalid value 11

func (*OutOfRangeError) Error

func (e *OutOfRangeError) Error() string

type PreprocessStage

type PreprocessStage int
const (
	PreprocessSkip PreprocessStage = iota
	PreprocessString
	PreprocessPtr
)

type Rule

type Rule struct {
	*rules.Rule

	ErrMsg []byte
	Type   typesutil.Type
}

func MustParseRuleStringWithType

func MustParseRuleStringWithType(ruleStr string, typ typesutil.Type) *Rule

func ParseRuleWithType

func ParseRuleWithType(ruleBytes []byte, typ typesutil.Type) (*Rule, error)

func (*Rule) SetDefaultValue

func (r *Rule) SetDefaultValue(defaultValue []byte)

func (*Rule) SetErrMsg

func (r *Rule) SetErrMsg(errMsg []byte)

func (*Rule) SetOptional

func (r *Rule) SetOptional(optional bool)

func (*Rule) String

func (r *Rule) String() string

type RuleModifier

type RuleModifier interface {
	SetOptional(optional bool)
	SetDefaultValue(defaultValue []byte)
	SetErrMsg(errMsg []byte)
}

type RuleProcessor

type RuleProcessor = func(rule RuleModifier)

type SliceValidator

type SliceValidator struct {
	ElemValidator Validator

	MinItems uint64
	MaxItems *uint64
}

Validator for slice

Rules:

@slice<ELEM_RULE>[minLen,maxLen]
@slice<ELEM_RULE>[length]

@slice<@string{A,B,C}>[,100]

Aliases

@array = @slice // and range must to be use length

func (SliceValidator) Names

func (SliceValidator) Names() []string

func (SliceValidator) New

func (SliceValidator) New(ctx context.Context, rule *Rule) (Validator, error)

func (*SliceValidator) String

func (validator *SliceValidator) String() string

func (*SliceValidator) Validate

func (validator *SliceValidator) Validate(v interface{}) error

func (*SliceValidator) ValidateReflectValue

func (validator *SliceValidator) ValidateReflectValue(rv reflect.Value) error

type StrLenMode

type StrLenMode string
const (
	StrLenModeLength    StrLenMode = "length"
	StrLenModeRuneCount StrLenMode = "rune_count"
)

type StrfmtValidator

type StrfmtValidator struct {
	// contains filtered or unexported fields
}

func NewRegexpStrfmtValidator

func NewRegexpStrfmtValidator(regexpStr string, name string, aliases ...string) *StrfmtValidator
Example
AlphaValidator := NewRegexpStrfmtValidator("^[a-zA-Z]+$", "alpha")

fmt.Println(AlphaValidator.Validate("a"))
fmt.Println(AlphaValidator.Validate("1"))
Output:

<nil>
alpha ^[a-zA-Z]+$ not match 1

func NewStrfmtValidator

func NewStrfmtValidator(validate func(v interface{}) error, name string, aliases ...string) *StrfmtValidator

func (*StrfmtValidator) Names

func (validator *StrfmtValidator) Names() []string

func (StrfmtValidator) New

func (validator StrfmtValidator) New(ctx context.Context, rule *Rule) (Validator, error)

func (*StrfmtValidator) String

func (validator *StrfmtValidator) String() string

func (*StrfmtValidator) TypeCheck

func (validator *StrfmtValidator) TypeCheck(rule *Rule) error

func (*StrfmtValidator) Validate

func (validator *StrfmtValidator) Validate(v interface{}) error

type StringValidator

type StringValidator struct {
	Pattern   string
	LenMode   StrLenMode
	MinLength uint64
	MaxLength *uint64
	Enums     []string
}

Validator for string

Rules:

@string/regexp/
@string{VALUE_1,VALUE_2,VALUE_3}
@string<StrLenMode>[from,to]
@string<StrLenMode>[length]

ranges

@string[min,max]
@string[length]
@string[1,10] // string length should large or equal than 1 and less or equal than 10
@string[1,]  // string length should large or equal than 1 and less than the maxinum of int32
@string[,1]  // string length should less than 1 and large or equal than 0
@string[10]  // string length should be equal 10

enumeration

@string{A,B,C} // should one of these values

regexp

@string/\w+/ // string values should match \w+

since we use / as wrapper for regexp, we need to use \ to escape /

length mode in parameter

@string<length> // use string length directly
@string<rune_count> // use rune count as string length

composes

@string<>[1,]

aliases:

@char = @string<rune_count>

func (StringValidator) Names

func (StringValidator) Names() []string

func (StringValidator) New

func (StringValidator) New(ctx context.Context, rule *Rule) (Validator, error)

func (*StringValidator) String

func (validator *StringValidator) String() string

func (*StringValidator) TypeCheck

func (validator *StringValidator) TypeCheck(rule *Rule) error

func (*StringValidator) Validate

func (validator *StringValidator) Validate(v interface{}) error

type StructValidator

type StructValidator struct {
	// contains filtered or unexported fields
}

func NewStructValidator

func NewStructValidator(namedTagKey string) *StructValidator
Example
type Named string

type SubPtrStruct struct {
	PtrInt   *int     `validate:"@int[1,]"`
	PtrFloat *float32 `validate:"@float[1,]"`
	PtrUint  *uint    `validate:"@uint[1,]"`
}

type SubStruct struct {
	Int   int     `json:"int" validate:"@int[1,]"`
	Float float32 `json:"float" validate:"@float[1,]"`
	Uint  uint    `json:"uint" validate:"@uint[1,]"`
}

type SomeStruct struct {
	JustRequired string
	CanEmpty     *string              `validate:"@string[0,]?"`
	String       string               `validate:"@string[1,]"`
	Named        Named                `validate:"@string[2,]"`
	PtrString    *string              `validate:"@string[3,]" default:"123"`
	SomeStringer *SomeTextMarshaler   `validate:"@string[20,]"`
	Slice        []string             `validate:"@slice<@string[1,]>"`
	SliceStruct  []SubStruct          `validate:"@slice"`
	Map          map[string]string    `validate:"@map<@string[2,],@string[1,]>"`
	MapStruct    map[string]SubStruct `validate:"@map<@string[2,],>"`
	Struct       SubStruct
	SubStruct
	*SubPtrStruct
}

validator := NewStructValidator("json")

ctx := ContextWithValidatorMgr(context.Background(), ValidatorMgrDefault)

structValidator, err := validator.New(ContextWithValidatorMgr(ctx, ValidatorMgrDefault), &Rule{
	Type: typesutil.FromRType(reflect.TypeOf(&SomeStruct{}).Elem()),
})
if err != nil {
	return
}

s := SomeStruct{
	Slice: []string{"", ""},
	SliceStruct: []SubStruct{
		{Int: 0},
	},
	Map: map[string]string{
		"1":  "",
		"11": "",
		"12": "",
	},
	MapStruct: map[string]SubStruct{
		"222": SubStruct{},
	},
}

errForValidate := structValidator.Validate(s)

errSet := map[string]string{}
errKeyPaths := make([]string, 0)

errForValidate.(*ErrorSet).Flatten().Each(func(fieldErr *FieldError) {
	errSet[fieldErr.Path.String()] = strconv.Quote(fieldErr.Error.Error())
	errKeyPaths = append(errKeyPaths, fieldErr.Path.String())
})

sort.Strings(errKeyPaths)

for i := range errKeyPaths {
	k := errKeyPaths[i]
	fmt.Println(k, errSet[k])
}
Output:

JustRequired "missing required field"
Map.1 "missing required field"
Map.1/key "string length should be larger than 2, but got invalid value 1"
Map.11 "missing required field"
Map.12 "missing required field"
MapStruct.222.float "missing required field"
MapStruct.222.int "missing required field"
MapStruct.222.uint "missing required field"
Named "missing required field"
PtrFloat "missing required field"
PtrInt "missing required field"
PtrString "missing required field"
PtrUint "missing required field"
SliceStruct[0].float "missing required field"
SliceStruct[0].int "missing required field"
SliceStruct[0].uint "missing required field"
Slice[0] "missing required field"
Slice[1] "missing required field"
SomeStringer "missing required field"
String "missing required field"
Struct.float "missing required field"
Struct.int "missing required field"
Struct.uint "missing required field"
float "missing required field"
int "missing required field"
uint "missing required field"

func (StructValidator) Names

func (StructValidator) Names() []string

func (*StructValidator) New

func (validator *StructValidator) New(ctx context.Context, rule *Rule) (Validator, error)

func (*StructValidator) String

func (validator *StructValidator) String() string

func (*StructValidator) Validate

func (validator *StructValidator) Validate(v interface{}) error

func (*StructValidator) ValidateReflectValue

func (validator *StructValidator) ValidateReflectValue(rv reflect.Value) error

type UintValidator

type UintValidator struct {
	BitSize uint

	Minimum          uint64
	Maximum          uint64
	MultipleOf       uint64
	ExclusiveMaximum bool
	ExclusiveMinimum bool

	Enums []uint64
}

Validator for uint

ranges

@uint[min,max]
@uint[1,10] // value should large or equal than 1 and less or equal than 10
@uint(1,10] // value should large than 1 and less or equal than 10
@uint[1,10) // value should large or equal than 1

@uint[1,)  // value should large or equal than 1 and less than the maxinum of int32
@uint[,1)  // value should less than 1 and large or equal than 0
@uint  // value should less or equal than maxinum of int32 and large or equal than 0

enumeration

@uint{1,2,3} // should one of these values

multiple of some int value

@uint{%multipleOf}
@uint{%2} // should be multiple of 2

bit size in parameter

@uint<8>
@uint<16>
@uint<32>
@uint<64>

composes

@uint<8>[1,]

aliases:

@uint8 = @uint<8>
@uint16 = @uint<16>
@uint32 = @uint<32>
@uint64 = @uint<64>

Tips: for JavaScript https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER and https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MIN_SAFE_INTEGER

uint<53>

func (UintValidator) Names

func (UintValidator) Names() []string

func (UintValidator) New

func (UintValidator) New(ctx context.Context, rule *Rule) (Validator, error)

func (*UintValidator) SetDefaults

func (validator *UintValidator) SetDefaults()

func (*UintValidator) String

func (validator *UintValidator) String() string

func (*UintValidator) TypeCheck

func (validator *UintValidator) TypeCheck(rule *Rule) error

func (*UintValidator) Validate

func (validator *UintValidator) Validate(v interface{}) error

type UnsupportedTypeError

type UnsupportedTypeError struct {
	// contains filtered or unexported fields
}

func NewUnsupportedTypeError

func NewUnsupportedTypeError(typ string, rule string, msgs ...string) *UnsupportedTypeError

func (*UnsupportedTypeError) Error

func (e *UnsupportedTypeError) Error() string

type Validator

type Validator interface {
	// Validate validate value
	Validate(v interface{}) error
	// String stringify validator rule
	String() string
}

type ValidatorCreator

type ValidatorCreator interface {
	// Names name and aliases of validator
	// we will register validator to validator set by these names
	Names() []string
	// New create new instance
	New(context.Context, *Rule) (Validator, error)
}

type ValidatorFactory

type ValidatorFactory struct {
	// contains filtered or unexported fields
}

func NewValidatorFactory

func NewValidatorFactory() *ValidatorFactory

func (*ValidatorFactory) Compile

func (f *ValidatorFactory) Compile(ctx context.Context, ruleBytes []byte, typ typesutil.Type, ruleProcessors ...RuleProcessor) (validator Validator, err error)

func (*ValidatorFactory) MustCompile

func (f *ValidatorFactory) MustCompile(ctx context.Context, rule []byte, typ typesutil.Type, ruleProcessors ...RuleProcessor) Validator

func (*ValidatorFactory) Register

func (f *ValidatorFactory) Register(validators ...ValidatorCreator)

type ValidatorLoader

type ValidatorLoader struct {
	ValidatorCreator ValidatorCreator
	Validator
	PreprocessStage

	DefaultValue []byte
	Optional     bool
	ErrMsg       []byte
}

func NewValidatorLoader

func NewValidatorLoader(validatorCreator ValidatorCreator) *ValidatorLoader

func (*ValidatorLoader) New

func (loader *ValidatorLoader) New(ctx context.Context, rule *Rule) (Validator, error)

func (*ValidatorLoader) String

func (loader *ValidatorLoader) String() string

func (*ValidatorLoader) Validate

func (loader *ValidatorLoader) Validate(v interface{}) error

type ValidatorMgr

type ValidatorMgr interface {
	// Compile compile rule string to validator
	Compile(context.Context, []byte, typesutil.Type, ...RuleProcessor) (Validator, error)
}

ValidatorMgr mgr for compiling validator

func ValidatorMgrFromContext

func ValidatorMgrFromContext(c context.Context) ValidatorMgr

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL