validator

package
v0.0.0-...-c5cf874 Latest Latest
Warning

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

Go to latest
Published: May 20, 2024 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package validator provides Validate

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrNotAStruct = errors.New("validate called on non-struct type")

Functions

func Add

func Add[F any](coll Collection, name string, validator func(Value *F, Default string) error)

Add adds a Validator to the provided collection of validators. Any previously validator of the same name is overwritten.

func AddSlice

func AddSlice[F any](coll Collection, name string, sep string, validator func(Value *F, Default string) error)

AddSlice adds a Validator to the provided collection of validators that validates a slice of the given type. The default is separated by sep.

func Validate

func Validate[T any](data *T, validators map[string]any) error

Validate validates an object of type T, setting defaults where appropriate.

T must be a struct type, when this is not the case, returns ErrNotAStruct. validators should contain a set of validators.

Validate iterates over the fields and tags of those fields as follows:

  • If the 'validate' tag is not the empty string, read the appropriate validator from the map, and call the function. If the element in the validators map does not exist, returns an error that unwraps to type UnknownValidator. If the element in the validators map is not a validator, returns an error that unwraps to type NotAValidator. If the type of validator function does not match the field type, returns an error that unwraps to type IncompatibleValidator.
  • If the 'recurse' tag is not the empty string, recurse into the struct type by calling Validate on it. If the annotated field is not a struct, return an error.

Any error is wrapped in a FieldError, indicating the field they occurred in. Recursive validate calls may result in FieldError wraps. For a description of struct tags, see reflect.StructTag.

Example

Demonstrates a passing validation.

var value struct {
	Number    int    `validate:"positive" default:"234"`
	String    string `validate:"nonempty" default:"stuff"`
	Recursive struct {
		Number int    `validate:"positive" default:"45"`
		String string `validate:"nonempty" default:"more"`
	} `recurse:"true"`
}

// Create a validator collection
collection := make(Collection, 2)

// positive checks if a number is positive
Add(collection, "positive", func(Value *int, Default string) error {
	// if value is unset, parse the default as a string
	if *Value == 0 {
		i, err := strconv.ParseInt(Default, 10, 64)
		if err != nil {
			return err
		}
		*Value = int(i)
		return nil
	}

	// check that we are actually positive!
	if *Value < 0 {
		return errors.New("not positive")
	}
	return nil
})

// nonempty checks that a string is not empty
Add(collection, "nonempty", func(Value *string, Default string) error {
	// set the default
	if *Value == "" {
		*Value = Default
	}

	// check that it is not empty
	if *Value == "" {
		return errors.New("empty string")
	}
	return nil
})

err := Validate(&value, collection)
fmt.Printf("%v\n", value)
fmt.Println(err)
Output:

{234 stuff {45 more}}
<nil>
Example (Fail)

Demonstrates a failing validation

// Create a validator collection
collection := make(Collection, 2)

// positive checks if a number is positive
Add(collection, "positive", func(Value *int, Default string) error {
	// if value is unset, parse the default as a string
	if *Value == 0 {
		i, err := strconv.ParseInt(Default, 10, 64)
		if err != nil {
			return err
		}
		*Value = int(i)
		return nil
	}

	// check that we are actually positive!
	if *Value < 0 {
		return errors.New("not positive")
	}
	return nil
})

// nonempty checks that a string is not empty
Add(collection, "nonempty", func(Value *string, Default string) error {
	// set the default
	if *Value == "" {
		*Value = Default
	}

	// check that it is not empty
	if *Value == "" {
		return errors.New("empty string")
	}
	return nil
})

// declare a value that uses the validators
var value struct {
	Number    int    `validate:"positive" default:"12"`
	String    string `validate:"nonempty" default:"stuff"`
	Recursive struct {
		Number int    `validate:"positive" default:"12"`
		String string `validate:"nonempty"`
	} `recurse:"true"`
}

err := Validate(&value, collection)

fmt.Printf("%v\n", value)
fmt.Println(err)
Output:

{12 stuff {12 }}
field "Recursive": field "String": empty string
Example (Invalid)

Demonstrates that validator types are checked.

// create a collection with a string validator
collection := make(Collection, 2)
collection["string"] = func(Value *string, Default string) error {
	panic("never reached")
}

// try to validate an int field with the incompatible validator
var value struct {
	Field int `validate:"string"`
}
err := Validate(&value, collection)

fmt.Println(err)
Output:

field "Field": validator "string": got type string, expected type int
Example (NotAStruct)

Demonstrates that Validate cannot be called on a non-struct type.

var value int
err := Validate(&value, nil)

fmt.Println(err)
Output:

validate called on non-struct type
Example (NotAValidator)

Demonstrates that non-validators cause an error.

// create a collection with something that isn't a validator
collection := make(Collection, 2)
collection["generic"] = "I_AM_NOT_A_VALIDATOR"

// try to validate a field with a non-validator
var value struct {
	Field int `validate:"generic"`
}
err := Validate(&value, collection)

fmt.Println(err)
Output:

field "Field": entry "generic" in validators is not a validator

Types

type Collection

type Collection map[string]any

Collection represents a set of validators. The zero value is not ready to use; it should be created using make().

A validator is a non-nil function with signature func(Value *F, Default string) error. Here F is the type of a value of a field. The value is the initialized value to be validated. The validator may perform arbitrary normalization on the value. Default is the default value (read from the 'default' tag). error should be an appropriate error that occurred.

A validator function is applied by calling it.

func (Collection) Call

func (coll Collection) Call(name string, field reflect.Value, Default string) error

Call calls the validator with the given name, on the given value, and with the provided default. See documentation of Validate for details.

type FieldError

type FieldError struct {
	Field string
	Err   error
}

FieldError wraps an error to indicate which field it occurred in.

func (FieldError) Error

func (fe FieldError) Error() string

func (FieldError) Unwrap

func (fe FieldError) Unwrap() error

type IncompatibleValidator

type IncompatibleValidator struct {
	Validator    string
	GotType      reflect.Type
	ExpectedType reflect.Type
}

IncompatibleValidator is returned when a validator in the validators map is incompatible

func (IncompatibleValidator) Error

func (iv IncompatibleValidator) Error() string

type NotAValidator

type NotAValidator string

NotAValidator is an error returned from Validate if an entry in the validators map is not a validator

func (NotAValidator) Error

func (nv NotAValidator) Error() string

type UnknownValidator

type UnknownValidator string

UnknownValidator is an error returned from Validate if a validator does not exist

func (UnknownValidator) Error

func (uv UnknownValidator) Error() string

Jump to

Keyboard shortcuts

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