validator

package
v1.0.5 Latest Latest
Warning

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

Go to latest
Published: Nov 27, 2022 License: Apache-2.0 Imports: 9 Imported by: 0

README

validator GoDoc

A powerful validator that supports struct tag expression.

Feature

  • Support for a variety of common operator
  • Support for accessing arrays, slices, members of the dictionary
  • Support access to any field in the current structure
  • Support access to nested fields, non-exported fields, etc.
  • Support registers validator function expression
  • Built-in len, sprintf, regexp, email, phone functions
  • Support simple mode, or specify error message mode
  • Use offset pointers to directly take values, better performance
  • Required go version ≥1.9

Example

package validator_test

import (
	"fmt"

	vd "github.com/21888/go-tagexpr-new/validator"
)

func Example() {
	type InfoRequest struct {
		Name         string   `vd:"($!='Alice'||(Age)$==18) && regexp('\\w')"`
		Age          int      `vd:"$>0"`
		Email        string   `vd:"email($)"`
		Phone1       string   `vd:"phone($)"`
		OtherPhones  []string `vd:"range($, phone(#v,'CN'))"`
		*InfoRequest `vd:"?"`
		Info1        *InfoRequest `vd:"?"`
		Info2        *InfoRequest `vd:"-"`
	}
	info := &InfoRequest{
		Name:        "Alice",
		Age:         18,
		Email:       "henrylee2cn@gmail.com",
		Phone1:      "+8618812345678",
		OtherPhones: []string{"18812345679", "18812345680"},
	}
	fmt.Println(vd.Validate(info))

	type A struct {
		A    int `vd:"$<0||$>=100"`
		Info interface{}
	}
	info.Email = "xxx"
	a := &A{A: 107, Info: info}
	fmt.Println(vd.Validate(a))
	type B struct {
		B string `vd:"len($)>1 && regexp('^\\w*$')"`
	}
	b := &B{"abc"}
	fmt.Println(vd.Validate(b) == nil)

	type C struct {
		C bool `vd:"@:(S.A)$>0 && !$; msg:'C must be false when S.A>0'"`
		S *A
	}
	c := &C{C: true, S: a}
	fmt.Println(vd.Validate(c))

	type D struct {
		d []string `vd:"@:len($)>0 && $[0]=='D'; msg:sprintf('invalid d: %v',$)"`
	}
	d := &D{d: []string{"x", "y"}}
	fmt.Println(vd.Validate(d))

	type E struct {
		e map[string]int `vd:"len($)==$['len']"`
	}
	e := &E{map[string]int{"len": 2}}
	fmt.Println(vd.Validate(e))

	// Customizes the factory of validation error.
	vd.SetErrorFactory(func(failPath, msg string) error {
		return fmt.Errorf(`{"succ":false, "error":"validation failed: %s"}`, failPath)
	})

	type F struct {
		f struct {
			g int `vd:"$%3==0"`
		}
	}
	f := &F{}
	f.f.g = 10
	fmt.Println(vd.Validate(f))

	fmt.Println(vd.Validate(map[string]*F{"a": f}))
	fmt.Println(vd.Validate(map[string]map[string]*F{"a": {"b": f}}))
	fmt.Println(vd.Validate([]map[string]*F{{"a": f}}))
	fmt.Println(vd.Validate(struct {
		A []map[string]*F
	}{A: []map[string]*F{{"x": f}}}))
	fmt.Println(vd.Validate(map[*F]int{f: 1}))
	fmt.Println(vd.Validate([][1]*F{{f}}))
	fmt.Println(vd.Validate((*F)(nil)))
	fmt.Println(vd.Validate(map[string]*F{}))
	fmt.Println(vd.Validate(map[string]map[string]*F{}))
	fmt.Println(vd.Validate([]map[string]*F{}))
	fmt.Println(vd.Validate([]*F{}))

	// Output:
	// <nil>
	// email format is incorrect
	// true
	// C must be false when S.A>0
	// invalid d: [x y]
	// invalid parameter: e
	// {"succ":false, "error":"validation failed: f.g"}
	// {"succ":false, "error":"validation failed: {v for k=a}.f.g"}
	// {"succ":false, "error":"validation failed: {v for k=a}{v for k=b}.f.g"}
	// {"succ":false, "error":"validation failed: [0]{v for k=a}.f.g"}
	// {"succ":false, "error":"validation failed: A[0]{v for k=x}.f.g"}
	// {"succ":false, "error":"validation failed: {k}.f.g"}
	// {"succ":false, "error":"validation failed: [0][0].f.g"}
	// unsupport data: nil
	// <nil>
	// <nil>
	// <nil>
	// <nil>
}

Syntax

Struct tag syntax spec:

type T struct {
	// Simple model
    Field1 T1 `tagName:"expression"`
	// Specify error message mode
    Field2 T2 `tagName:"@:expression; msg:expression2"`
	// Omit it
    Field3 T3 `tagName:"-"`
    // Omit it when it is nil
    Field4 T4 `tagName:"?"`
    ...
}
Operator or Operand Explain
true false boolean
0 0.0 float64 "0"
'' String
\\' Escape ' delims in string
\" Escape " delims in string
nil nil, undefined
! not
+ Digital addition or string splicing
- Digital subtraction or negative
* Digital multiplication
/ Digital division
% division remainder, as: float64(int64(a)%int64(b))
== eq
!= ne
> gt
>= ge
< lt
<= le
&& Logic and
|| Logic or
() Expression group
(X)$ Struct field value named X
(X.Y)$ Struct field value named X.Y
$ Shorthand for (X)$, omit (X) to indicate current struct field value
(X)$['A'] Map value with key A or struct A sub-field in the struct field X
(X)$[0] The 0th element or sub-field of the struct field X(type: map, slice, array, struct)
len((X)$) Built-in function len, the length of struct field X
mblen((X)$) the length of string field X (character number)
regexp('^\\w*$', (X)$) Regular match the struct field X, return boolean
regexp('^\\w*$') Regular match the current struct field, return boolean
sprintf('X value: %v', (X)$) fmt.Sprintf, format the value of struct field X
range(KvExpr, forEachExpr) Iterate over an array, slice, or dictionary
- #k is the element key var
- #v is the element value var
- ## is the number of elements
- e.g. example
email((X)$) Regular match the struct field X, return true if it is email
phone((X)$,<'defaultRegion'>) Regular match the struct field X, return true if it is phone
in((X)$, enum_1, ...enum_n) Check if the first parameter is one of the enumerated parameters

Operator priority(high -> low):

  • () ! bool float64 string nil
  • * / %
  • + -
  • < <= > >=
  • == !=
  • &&
  • ||

Documentation

Overview

Package validator is a powerful validator that supports struct tag expression.

Copyright 2019 Bytedance Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Example
package main

import (
	"fmt"

	vd "github.com/21888/go-tagexpr-new/validator"
)

func main() {
	type InfoRequest struct {
		Name         string   `vd:"($!='Alice'||(Age)$==18) && regexp('\\w')"`
		Age          int      `vd:"$>0"`
		Email        string   `vd:"email($)"`
		Phone1       string   `vd:"phone($)"`
		OtherPhones  []string `vd:"range($, phone(#v,'CN'))"`
		*InfoRequest `vd:"?"`
		Info1        *InfoRequest `vd:"?"`
		Info2        *InfoRequest `vd:"-"`
	}
	info := &InfoRequest{
		Name:        "Alice",
		Age:         18,
		Email:       "henrylee2cn@gmail.com",
		Phone1:      "+8618812345678",
		OtherPhones: []string{"18812345679", "18812345680"},
	}
	fmt.Println(vd.Validate(info))

	type A struct {
		A    int `vd:"$<0||$>=100"`
		Info interface{}
	}
	info.Email = "xxx"
	a := &A{A: 107, Info: info}
	fmt.Println(vd.Validate(a))
	type B struct {
		B string `vd:"len($)>1 && regexp('^\\w*$')"`
	}
	b := &B{"abc"}
	fmt.Println(vd.Validate(b) == nil)

	type C struct {
		C bool `vd:"@:(S.A)$>0 && !$; msg:'C must be false when S.A>0'"`
		S *A
	}
	c := &C{C: true, S: a}
	fmt.Println(vd.Validate(c))

	type D struct {
		d []string `vd:"@:len($)>0 && $[0]=='D'; msg:sprintf('invalid d: %v',$)"`
	}
	d := &D{d: []string{"x", "y"}}
	fmt.Println(vd.Validate(d))

	type E struct {
		e map[string]int `vd:"len($)==$['len']"`
	}
	e := &E{map[string]int{"len": 2}}
	fmt.Println(vd.Validate(e))

	// Customizes the factory of validation error.
	vd.SetErrorFactory(func(failPath, msg string) error {
		return fmt.Errorf(`{"succ":false, "error":"validation failed: %s"}`, failPath)
	})

	type F struct {
		f struct {
			g int `vd:"$%3==0"`
		}
	}
	f := &F{}
	f.f.g = 10
	fmt.Println(vd.Validate(f))

	fmt.Println(vd.Validate(map[string]*F{"a": f}))
	fmt.Println(vd.Validate(map[string]map[string]*F{"a": {"b": f}}))
	fmt.Println(vd.Validate([]map[string]*F{{"a": f}}))
	fmt.Println(vd.Validate(struct {
		A []map[string]*F
	}{A: []map[string]*F{{"x": f}}}))
	fmt.Println(vd.Validate(map[*F]int{f: 1}))
	fmt.Println(vd.Validate([][1]*F{{f}}))
	fmt.Println(vd.Validate((*F)(nil)))
	fmt.Println(vd.Validate(map[string]*F{}))
	fmt.Println(vd.Validate(map[string]map[string]*F{}))
	fmt.Println(vd.Validate([]map[string]*F{}))
	fmt.Println(vd.Validate([]*F{}))

}
Output:

<nil>
email format is incorrect
true
C must be false when S.A>0
invalid d: [x y]
invalid parameter: e
{"succ":false, "error":"validation failed: f.g"}
{"succ":false, "error":"validation failed: {v for k=a}.f.g"}
{"succ":false, "error":"validation failed: {v for k=a}{v for k=b}.f.g"}
{"succ":false, "error":"validation failed: [0]{v for k=a}.f.g"}
{"succ":false, "error":"validation failed: A[0]{v for k=x}.f.g"}
{"succ":false, "error":"validation failed: {k}.f.g"}
{"succ":false, "error":"validation failed: [0][0].f.g"}
unsupport data: nil
<nil>
<nil>
<nil>
<nil>

Index

Examples

Constants

View Source
const (
	// MatchExprName the name of the expression used for validation
	MatchExprName = tagexpr.DefaultExprName
	// ErrMsgExprName the name of the expression used to specify the message
	// returned when validation failed
	ErrMsgExprName = "msg"
)

Variables

View Source
var ErrInvalidWithoutMsg = errors.New("")

ErrInvalidWithoutMsg verification error without error message.

Functions

func MustRegFunc

func MustRegFunc(funcName string, fn func(args ...interface{}) error, force ...bool)

MustRegFunc registers validator function expression. NOTE:

panic if exist error;
example: phone($) or phone($,'CN');
If @force=true, allow to cover the existed same @funcName;
The go number types always are float64;
The go string types always are string.

func RegFunc

func RegFunc(funcName string, fn func(args ...interface{}) error, force ...bool) error

RegFunc registers validator function expression. NOTE:

example: phone($) or phone($,'CN');
If @force=true, allow to cover the existed same @funcName;
The go number types always are float64;
The go string types always are string.

func SetErrorFactory

func SetErrorFactory(errFactory func(fieldSelector, msg string) error)

SetErrorFactory customizes the factory of validation error for the default validator. NOTE:

The tag name is 'vd'

func Validate

func Validate(value interface{}, checkAll ...bool) error

Validate uses the default validator to validate whether the fields of value is valid. NOTE:

The tag name is 'vd'
If checkAll=true, validate all the error.

Types

type Error

type Error struct {
	FailPath, Msg string
}

Error validate error

func (*Error) Error

func (e *Error) Error() string

Error implements error interface.

type Validator

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

Validator struct fields validator

func Default

func Default() *Validator

Default returns the default validator. NOTE:

The tag name is 'vd'

func New

func New(tagName string) *Validator

New creates a struct fields validator.

func (*Validator) SetErrorFactory

func (v *Validator) SetErrorFactory(errFactory func(failPath, msg string) error) *Validator

SetErrorFactory customizes the factory of validation error. NOTE:

If errFactory==nil, the default is used

func (*Validator) VM

func (v *Validator) VM() *tagexpr.VM

VM returns the struct tag expression interpreter.

func (*Validator) Validate

func (v *Validator) Validate(value interface{}, checkAll ...bool) error

Validate validates whether the fields of value is valid. NOTE:

If checkAll=true, validate all the error.

Jump to

Keyboard shortcuts

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