validator

package module
v1.5.4 Latest Latest
Warning

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

Go to latest
Published: Jan 28, 2022 License: MIT Imports: 18 Imported by: 3

README

Validator

GoDoc Widget Build Status codecov Go Report Card

Validator is value validations for struct but not only for struct.

Overviews

built-in validators:

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:

@string: https://godoc.org/github.com/go-liewhite/validator#StringValidator

@uint: https://godoc.org/github.com/go-liewhite/validator#UintValidator

@int: https://godoc.org/github.com/go-liewhite/validator#IntValidator

@float: https://godoc.org/github.com/go-liewhite/validator#FloatValidator

@struct: https://godoc.org/github.com/go-liewhite/validator#StructValidator

@map: https://godoc.org/github.com/go-liewhite/validator#MapValidator

@slice: https://godoc.org/github.com/go-liewhite/validator#SliceValidator

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 UintRange

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

Types

type FloatValidator

type FloatValidator struct {
	MaxDigits     uint
	DecimalDigits *uint

	Minimum          *float64
	Maximum          *float64
	ExclusiveMaximum bool
	ExclusiveMinimum bool

	MultipleOf float64

	Enums map[float64]string
}

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 map[int64]string
}

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 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 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) String

func (r *Rule) String() string

type RuleProcessor

type RuleProcessor func(rule *Rule)

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 int
const (
	STR_LEN_MODE__LENGTH StrLenMode = iota
	STR_LEN_MODE__RUNE_COUNT
)

func ParseStrLenMode

func ParseStrLenMode(s string) (StrLenMode, error)

func (StrLenMode) String

func (m StrLenMode) String() string

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 {
	Enums   map[string]string
	Pattern *regexp.Regexp
	LenMode StrLenMode

	MinLength uint64
	MaxLength *uint64
}

Validator for string

Rules:

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.(*errors.ErrorSet).Flatten().Each(func(fieldErr *errors.FieldError) {
	errSet[fieldErr.Field.String()] = strconv.Quote(fieldErr.Error.Error())
	errKeyPaths = append(errKeyPaths, fieldErr.Field.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 map[uint64]string
}

Validator for uint

Rules:

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 Validator

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

type ValidatorCreator

type ValidatorCreator interface {
	// name and aliases of validator
	// we will register validator to validator set by these names
	Names() []string
	// 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, ruleProcessor RuleProcessor) (Validator, error)

func (*ValidatorFactory) MustCompile

func (f *ValidatorFactory) MustCompile(ctx context.Context, rule []byte, typ typesutil.Type, ruleProcessor 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 rule string to validator
	Compile(context.Context, []byte, typesutil.Type, RuleProcessor) (Validator, error)
}

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