validating

package module
v2.1.4 Latest Latest
Warning

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

Go to latest
Published: Mar 16, 2022 License: MIT Imports: 6 Imported by: 3

README

validating

A Go library for validating structs, maps and slices.

Features

  1. Simple

    Simple and stupid, no magic involved.

  2. Type-safe

    Schema is defined in Go, which is type-safer (and more powerful) than traditional struct tags.

  3. Flexible

    • Validators are composite.
    • Nested struct validation is well supported.
    • Schema can be defined inside or outside struct.
    • Validator customizations are made easy.
  4. No reflection

Installation

$ go get -u github.com/RussellLuo/validating/v2

Validator factories and validators

To be strict, this library has a conceptual distinction between validator factory and validator.

A validator factory is a function used to create a validator, which will do the actual validation.

Built-in validator factories
Extension validator factories
Validator customizations

Examples

Documentation

Check out the Godoc.

Thanks

This library borrows some ideas from the following libraries:

License

MIT

Documentation

Overview

Example (Customizations)
package main

import (
	"fmt"
	"time"

	v "github.com/RussellLuo/validating/v2"
)

func validate(field v.Field) v.Errors {
	switch t := field.ValuePtr.(type) {
	case *map[string]time.Time:
		if *t == nil {
			return v.NewErrors(field.Name, v.ErrInvalid, "is empty")
		}
		return nil
	default:
		return v.NewErrors(field.Name, v.ErrUnsupported, "is unsupported")
	}
}

type MyValidator struct{}

func (mv *MyValidator) Validate(field v.Field) v.Errors {
	return validate(field)
}

func main() {
	var value map[string]time.Time

	// do validation by funcValidator
	funcValidator := v.Func(validate)
	errs := v.Validate(v.Schema{
		v.F("value", &value): funcValidator,
	})
	fmt.Printf("errs from funcValidator: %+v\n", errs)

	// do validation by structValidator
	structValidator := &MyValidator{}
	errs = v.Validate(v.Schema{
		v.F("value", &value): structValidator,
	})
	fmt.Printf("errs from structValidator: %+v\n", errs)

}
Output:

errs from funcValidator: value: INVALID(is empty)
errs from structValidator: value: INVALID(is empty)
Example (NestedStruct)
package main

import (
	"fmt"

	v "github.com/RussellLuo/validating/v2"
)

type Address struct {
	Country, Province, City string
}

type Person struct {
	Name    string
	Age     int
	Address Address
}

func main() {
	p := Person{}
	err := v.Validate(v.Schema{
		v.F("name", &p.Name): v.Len(1, 5),
		v.F("age", &p.Age):   v.Gte(10),
		v.F("address", &p.Address): v.Schema{
			v.F("country", &p.Address.Country):  v.Nonzero(),
			v.F("province", &p.Address.Country): v.Nonzero(),
			v.F("city", &p.Address.City):        v.Nonzero(),
		},
	})
	fmt.Printf("err: %+v\n", err)
}
Output:

Example (NestedStructMap)
package main

import (
	"fmt"

	v "github.com/RussellLuo/validating/v2"
)

type Member struct {
	Name string
}

type Person1 struct {
	Name   string
	Age    int
	Family map[string]*Member
}

func makeSchema1(p *Person1) v.Schema {
	return v.Schema{
		v.F("name", &p.Name): v.Len(1, 5),
		v.F("age", &p.Age):   v.Nonzero(),
		v.F("family", &p.Family): v.ZeroOr(
			v.Map(func() map[string]v.Schema {
				schemas := make(map[string]v.Schema)
				for relation, member := range p.Family {
					schemas[relation] = v.Schema{
						v.F("name", &member.Name): v.Len(10, 15).Msg("is too long"),
					}
				}
				return schemas
			}),
		),
	}
}

func main() {
	p1 := Person1{}
	err := v.Validate(makeSchema1(&p1))
	fmt.Printf("err of p1: %+v\n", err)

	p2 := Person1{Family: map[string]*Member{
		"father": {"father's name"},
		"mother": {"mother's name is long"},
	}}
	err = v.Validate(makeSchema1(&p2))
	fmt.Printf("err of p2: %+v\n", err)
}
Output:

Example (NestedStructPointer)
package main

import (
	"fmt"

	v "github.com/RussellLuo/validating/v2"
)

type Address2 struct {
	Country, Province, City string
}

type Person2 struct {
	Name    string
	Age     int
	Address *Address2
}

func makeSchema2(p *Person2) v.Schema {
	return v.Schema{
		v.F("name", &p.Name): v.Len(1, 5),
		v.F("age", &p.Age):   v.Lte(50),
		v.F("address", &p.Address): v.All(
			v.Assert(p.Address != nil).Msg("is nil"),
			v.Lazy(func() v.Validator {
				return v.Schema{
					v.F("country", &p.Address.Country):  v.Nonzero(),
					v.F("province", &p.Address.Country): v.Nonzero(),
					v.F("city", &p.Address.City):        v.Nonzero(),
				}
			}),
		),
	}
}

func main() {
	p1 := Person2{}
	err := v.Validate(makeSchema2(&p1))
	fmt.Printf("err of p1: %+v\n", err)

	p2 := Person2{Age: 60, Address: &Address2{}}
	err = v.Validate(makeSchema2(&p2))
	fmt.Printf("err of p2: %+v\n", err)
}
Output:

Example (NestedStructSchemaInside)
package main

import (
	"fmt"

	v "github.com/RussellLuo/validating/v2"
)

type Address3 struct {
	Country, Province, City string
}

func (a *Address3) Schema() v.Schema {
	return v.Schema{
		v.F("country", &a.Country):  v.Nonzero(),
		v.F("province", &a.Country): v.Nonzero(),
		v.F("city", &a.City):        v.Nonzero(),
	}
}

type Person3 struct {
	Name    string
	Age     int
	Address Address3
}

func (p *Person3) Schema() v.Schema {
	return v.Schema{
		v.F("name", &p.Name):       v.Len(1, 5),
		v.F("age", &p.Age):         v.Gte(10),
		v.F("address", &p.Address): p.Address.Schema(),
	}
}

func main() {
	p := Person3{}
	err := v.Validate(p.Schema())
	fmt.Printf("err: %+v\n", err)
}
Output:

Example (NestedStructSlice)
package main

import (
	"fmt"

	v "github.com/RussellLuo/validating/v2"
)

type Phone struct {
	Number, Remark string
}

type Person4 struct {
	Name   string
	Age    int
	Phones []*Phone
}

func makeSchema4(p *Person4) v.Schema {
	return v.Schema{
		v.F("name", &p.Name): v.Len(1, 5),
		v.F("age", &p.Age):   v.Nonzero(),
		v.F("phones", &p.Phones): v.ZeroOr(
			v.Slice(func() (schemas []v.Schema) {
				for _, phone := range p.Phones {
					schemas = append(schemas, v.Schema{
						v.F("number", &phone.Number): v.Nonzero(),
						v.F("remark", &phone.Remark): v.Len(5, 7),
					})
				}
				return
			}),
		),
	}
}

func main() {
	p1 := Person4{}
	err := v.Validate(makeSchema4(&p1))
	fmt.Printf("err of p1: %+v\n", err)

	p2 := Person4{Phones: []*Phone{
		{"13011112222", "private"},
		{"13033334444", "business"},
	}}
	err = v.Validate(makeSchema4(&p2))
	fmt.Printf("err of p2: %+v\n", err)
}
Output:

Example (SimpleMap)
package main

import (
	"fmt"

	v "github.com/RussellLuo/validating/v2"
)

func main() {
	ages := map[string]int{
		"foo": 0,
		"bar": 1,
	}
	err := v.Validate(v.Map(func() map[string]v.Schema {
		schemas := make(map[string]v.Schema)
		for name, age := range ages {
			age := age
			schemas[name] = v.Value(&age, v.Nonzero())
		}
		return schemas
	}))
	fmt.Printf("%+v\n", err)

}
Output:

[foo]: INVALID(is zero valued)
Example (SimpleSlice)
package main

import (
	"fmt"

	v "github.com/RussellLuo/validating/v2"
)

func main() {
	names := []string{"", "foo"}
	err := v.Validate(v.Slice(func() (schemas []v.Schema) {
		for _, name := range names {
			name := name
			schemas = append(schemas, v.Value(&name, v.Nonzero()))
		}
		return schemas
	}))
	fmt.Printf("%+v\n", err)

}
Output:

[0]: INVALID(is zero valued)
Example (SimpleStruct)
package main

import (
	"fmt"

	v "github.com/RussellLuo/validating/v2"
)

type Person5 struct {
	Name string
	Age  int
}

func main() {
	p := Person5{Age: 1}
	err := v.Validate(v.Schema{
		v.F("name", &p.Name): v.Len(1, 5).Msg("length is not between 1 and 5"),
		v.F("age", &p.Age):   v.Nonzero(),
	})
	fmt.Printf("%+v\n", err)

}
Output:

name: INVALID(length is not between 1 and 5)
Example (SimpleValue)
package main

import (
	"fmt"

	v "github.com/RussellLuo/validating/v2"
)

func main() {
	value := 0
	err := v.Validate(v.Value(&value, v.Range(1, 5)))
	fmt.Printf("%+v\n", err)

}
Output:

INVALID(is not between given range)

Index

Examples

Constants

View Source
const (
	ErrUnsupported  = "UNSUPPORTED"
	ErrUnrecognized = "UNRECOGNIZED"
	ErrInvalid      = "INVALID"
)

Variables

View Source
var And = All

And is an alias of All.

View Source
var Array = Slice

Array is an alias of Slice.

View Source
var Or = Any

Or is an alias of Any.

Functions

This section is empty.

Types

type AnyValidator added in v2.1.2

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

AnyValidator is a validator that allows users to change the returned errors by calling LastError().

func Any

func Any(validators ...Validator) *AnyValidator

Any is a composite validator factory used to create a validator, which will succeed as long as any sub-validator succeeds.

func (*AnyValidator) LastError added in v2.1.3

func (av *AnyValidator) LastError() *AnyValidator

LastError makes AnyValidator return the error from the last validator if all inner validators fail.

func (*AnyValidator) Validate added in v2.1.2

func (av *AnyValidator) Validate(field Field) Errors

Validate delegates the actual validation to its inner validators.

type Error

type Error interface {
	error
	Field() string
	Kind() string
	Message() string
}

func NewError

func NewError(field, kind, message string) Error

type Errors

type Errors []Error

func NewErrors

func NewErrors(field, kind, message string) (errs Errors)

func Validate

func Validate(v Validator) (errs Errors)

Validate invokes v.Validate with an empty field.

func (*Errors) Append

func (e *Errors) Append(err Error)

func (Errors) Error

func (e Errors) Error() string

func (*Errors) Extend

func (e *Errors) Extend(errs Errors)

type Field

type Field struct {
	Name     string
	ValuePtr interface{}
}

Field represents a (Name, ValuePtr) pair need to be validated.

func F

func F(name string, valuePtr interface{}) Field

F is a shortcut for creating an instance of Field.

type Func added in v2.1.0

type Func func(field Field) Errors

Func is an adapter to allow the use of ordinary functions as validators. If f is a function with the appropriate signature, Func(f) is a Validator that calls f.

func (Func) Validate added in v2.1.0

func (f Func) Validate(field Field) Errors

Validate calls f(field).

type MessageValidator

type MessageValidator struct {
	Message   string
	Validator Validator
}

MessageValidator is a validator that allows users to customize the INVALID error message by calling Msg().

func Assert

func Assert(b bool) (mv *MessageValidator)

Assert is a leaf validator factory used to create a validator, which will succeed only when the boolean expression evaluates to true.

func Eq

func Eq(value interface{}) (mv *MessageValidator)

Eq is a leaf validator factory used to create a validator, which will succeed when the field's value equals the given value.

func Gt

func Gt(value interface{}) (mv *MessageValidator)

Gt is a leaf validator factory used to create a validator, which will succeed when the field's value is greater than the given value.

func Gte

func Gte(value interface{}) (mv *MessageValidator)

Gte is a leaf validator factory used to create a validator, which will succeed when the field's value is greater than or equal to the given value.

func In

func In(values ...interface{}) (mv *MessageValidator)

In is a leaf validator factory used to create a validator, which will succeed when the field's value is equal to one of the given values.

func Len

func Len(min, max int) (mv *MessageValidator)

Len is a leaf validator factory used to create a validator, which will succeed when the field's length is between min and max.

func Lt

func Lt(value interface{}) (mv *MessageValidator)

Lt is a leaf validator factory used to create a validator, which will succeed when the field's value is lower than the given value.

func Lte

func Lte(value interface{}) (mv *MessageValidator)

Lte is a leaf validator factory used to create a validator, which will succeed when the field's value is lower than or equal to the given value.

func Match added in v2.1.0

func Match(re *regexp.Regexp) (mv *MessageValidator)

Match is a leaf validator factory used to create a validator, which will succeed when the field's value matches the given regular expression.

func Ne

func Ne(value interface{}) (mv *MessageValidator)

Ne is a leaf validator factory used to create a validator, which will succeed when the field's value does not equal the given value.

func Nin

func Nin(values ...interface{}) (mv *MessageValidator)

Nin is a leaf validator factory used to create a validator, which will succeed when the field's value is not equal to any of the given values.

func Nonzero

func Nonzero() (mv *MessageValidator)

Nonzero is a leaf validator factory used to create a validator, which will succeed when the field's value is nonzero.

func Not

func Not(validator Validator) (mv *MessageValidator)

Not is a composite validator factory used to create a validator, which will succeed when the given validator fails.

func Range

func Range(min, max interface{}) (mv *MessageValidator)

Range is a shortcut of `All(Gte(min), Lte(max))`.

func RuneCount

func RuneCount(min, max int) (mv *MessageValidator)

RuneCount is a leaf validator factory used to create a validator, which will succeed when the number of runes in the field's value is between min and max.

func Zero added in v2.1.3

func Zero() (mv *MessageValidator)

Zero is a leaf validator factory used to create a validator, which will succeed when the field's value is zero.

func (*MessageValidator) Msg

Msg sets the INVALID error message.

func (*MessageValidator) Validate

func (mv *MessageValidator) Validate(field Field) Errors

Validate delegates the actual validation to its inner validator.

type Schema

type Schema map[Field]Validator

Schema is a field mapping, which defines the corresponding validator for each field.

func Value added in v2.1.0

func Value(valuePtr interface{}, validator Validator) Schema

Value is a shortcut function used to create a schema for a simple value.

func (Schema) Validate added in v2.1.0

func (s Schema) Validate(field Field) (errs Errors)

Validate validates fields per the given according to the schema.

type Validator

type Validator interface {
	Validate(field Field) Errors
}

Validator is an interface for representing a validating's validator.

func All

func All(validators ...Validator) Validator

All is a composite validator factory used to create a validator, which will succeed only when all sub-validators succeed.

func Lazy

func Lazy(f func() Validator) Validator

Lazy is a composite validator factory used to create a validator, which will call f only as needed, to delegate the actual validation to the validator returned by f.

func Map added in v2.1.0

func Map(f func() map[string]Schema) Validator

Map is a composite validator factory used to create a validator, which will do the validation per the schemas associated with a map.

func Slice added in v2.1.0

func Slice(f func() []Schema) Validator

Slice is a composite validator factory used to create a validator, which will do the validation per the schemas associated with a slice.

func ZeroOr added in v2.1.4

func ZeroOr(validator Validator) Validator

ZeroOr is a composite validator factory used to create a validator, which will succeed if the field's value is zero, or if the given validator succeeds.

ZeroOr will return the error from the given validator if it fails.

Jump to

Keyboard shortcuts

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