validator

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Jul 7, 2026 License: Apache-2.0 Imports: 13 Imported by: 0

README

validator-go

FluentValidation-style struct validation for Go.


CI Go Reference License

Installation

go get github.com/Jamess-Lucass/validator-go

Requires Go 1.18+.

Quick Start

Create a validator for a struct pointer, declare rules against its fields, then call Validate. Every rule attaches the same way: a free function taking the validator and a pointer to the field.

import (
    validator "github.com/Jamess-Lucass/validator-go"
)

type User struct {
    Name  string `json:"name"`
    Email string `json:"email"`
    Age   int    `json:"age"`
}

user := User{Name: "J", Email: "bad", Age: -1}

v, err := validator.New(&user)
if err != nil {
    // &user must be a non-nil pointer to a struct
    return
}
validator.String(v, &user.Name).NotEmpty().Min(2).Max(50)
validator.String(v, &user.Email).NotEmpty().Email()
validator.Number(v, &user.Age).Gte(0).Lte(150)

result := v.Validate()

result.IsValid() // false
result.Errors    // [{Field: "name", Message: "must be at least 2 characters"}, ...]

New returns an error if the argument is not a non-nil pointer to a struct. Field names are resolved by reflection, preferring the json struct tag and falling back to the Go field name. Rules read the field's value at Validate time, so you can declare them up front and mutate the struct in between.

The rule subpackage provides the same rules as standalone values for unstructured data and per-element validation; see Unstructured Objects below.

String

Named string types (type ID string) work too.

validator.String(v, &s.Field).NotEmpty()
validator.String(v, &s.Field).Min(n)
validator.String(v, &s.Field).Max(n)
validator.String(v, &s.Field).Length(min, max)
validator.String(v, &s.Field).Email()
validator.String(v, &s.Field).URL()
validator.String(v, &s.Field).Matches(`^[a-z]+-\d+$`)
validator.String(v, &s.Field).Includes("substr")
validator.String(v, &s.Field).StartsWith("prefix")
validator.String(v, &s.Field).EndsWith("suffix")
validator.String(v, &s.Field).OneOf("active", "disabled")
validator.String(v, &s.Field).Must(func(val string) bool { return true })
validator.String(v, &s.Field).WithMessage("custom error")

Min, Max, and Length count runes (Unicode code points), not bytes. Matches compiles the pattern once when the rule is declared; like regexp.MustCompile, an invalid pattern panics.

Numbers

Number works on any real numeric type, from int and float64 to named types like type Age int. The type is inferred from the field pointer.

validator.Number(v, &s.Field).NotEmpty() // must not be zero
validator.Number(v, &s.Field).Gt(n)
validator.Number(v, &s.Field).Gte(n)
validator.Number(v, &s.Field).Lt(n)
validator.Number(v, &s.Field).Lte(n)
validator.Number(v, &s.Field).Positive()
validator.Number(v, &s.Field).Negative()
validator.Number(v, &s.Field).Nonnegative()
validator.Number(v, &s.Field).Nonpositive()
validator.Number(v, &s.Field).OneOf(1, 2, 3)
validator.Number(v, &s.Field).MultipleOf(n)
validator.Number(v, &s.Field).Finite() // rejects NaN and ±Inf
validator.Number(v, &s.Field).Must(func(val int) bool { return true })

Integer MultipleOf is exact; float MultipleOf uses a magnitude-relative tolerance. Complex numbers aren't ordered, so they get only presence and custom rules:

validator.Complex(v, &s.Amplitude).NotEmpty() // must be != 0

Bool

Named bool types work too.

validator.Bool(v, &s.Field).NotEmpty() // must be true
validator.Bool(v, &s.Field).Must(func(val bool) bool { return true })

Time

validator.Time(v, &s.Field).NotEmpty() // must not be the zero time
validator.Time(v, &s.Field).After(t)
validator.Time(v, &s.Field).Before(t)
validator.Time(v, &s.Field).Must(func(val time.Time) bool { return true })

UUID

Validates github.com/google/uuid values.

validator.UUID(v, &s.ID).NotEmpty() // must not be the nil UUID (all zeros)
validator.UUID(v, &s.ID).Must(func(val uuid.UUID) bool { return val.Version() == 4 })
validator.UUID(v, &s.ID).WithMessage("custom error")

Slice

Named slice types (type Tags []string) work too.

validator.Slice(v, &s.Tags).NotNil()  // fails on a nil slice (distinct from empty)
validator.Slice(v, &s.Tags).NotEmpty()
validator.Slice(v, &s.Tags).Min(n)
validator.Slice(v, &s.Tags).Max(n)
validator.Slice(v, &s.Tags).Length(min, max)
validator.Slice(v, &s.Tags).Must(func(val []string) bool { return true })

// Validate each primitive element
validator.Slice(v, &s.Tags).EachValue(rule.String().NotEmpty().Min(2))

// Validate each struct element
validator.Slice(v, &s.Items).Each(func(item *Item, sv *validator.Validator) {
    validator.String(sv, &item.Name).NotEmpty()
    validator.Number(sv, &item.Quantity).Gte(1)
})

Arrays

Slices use the typed Slice above. Fixed-size arrays can't be expressed with Go generics (the length is part of the type), so Array validates them by reflection:

type Matrix struct {
    Row [3]int `json:"row"`
}

validator.Array(v, &m.Row).Min(1).EachValue(rule.Int().Positive())

Array values are also accepted anywhere a slice is (maps, SliceOf, EachValue).

Maps

Map validates a typed map field, such as a set of labels or HTTP headers. Named map types (type Labels map[string]string) work too. Entries are checked in sorted key order so errors always come out in the same order, even though Go randomizes map iteration. Pointer keys are shown by the value they point to, since an address would change from run to run.

type Deployment struct {
    Name       string               `json:"name"`
    Labels     map[string]string    `json:"labels"`
    Containers map[string]Container `json:"containers"`
}

validator.Map(v, &d.Labels).NotNil()   // fails on a nil map (distinct from empty)
validator.Map(v, &d.Labels).NotEmpty()
validator.Map(v, &d.Labels).Min(n)
validator.Map(v, &d.Labels).Max(n)
validator.Map(v, &d.Labels).Length(min, max)
validator.Map(v, &d.Labels).HasKey("env")
validator.Map(v, &d.Labels).Must(func(m map[string]string) bool { return true })

// Validate every value: "labels[env]: must not be empty"
validator.Map(v, &d.Labels).EachValue(rule.String().NotEmpty())

// Validate every key: "labels[e]: key must be at least 2 characters"
validator.Map(v, &d.Labels).EachKey(rule.String().Min(2))

// Validate struct values, with errors like "containers[web].image: must not be empty"
validator.Map(v, &d.Containers).Each(func(name string, c *Container, sv *validator.Validator) {
    validator.String(sv, &c.Image).NotEmpty()
    validator.Number(sv, &c.Replicas).Gte(1)
})

Go map values aren't addressable, so Each passes a pointer to a copy of the value.

Nullable Fields

Pointer fields (*string, *int, *time.Time, ...) are skipped when nil. Pass the pointer directly and use NotNil() to require a value.

type Order struct {
    Notes       *string    `json:"notes"`
    ScheduledAt *time.Time `json:"scheduled_at"`
}

v, _ := validator.New(&order)
validator.String(v, order.Notes).Min(1).Max(500)                       // skipped if nil
validator.Time(v, order.ScheduledAt).NotNil().WithName("scheduled_at") // error if nil

A nil pointer has no address, so its field name cannot be resolved by reflection and the error's Field falls back to "unknown". Chain WithName("...") (available on every rule type) to give such fields a stable name in the error output. The same applies when two pointer fields share one target: the address alone cannot tell them apart, so name the rules explicitly.

Nested & Embedded Structs

Nested struct fields resolve with dot-notation. Embedded struct fields resolve without a prefix.

type Address struct {
    City string `json:"city"`
}

type User struct {
    Base                       // embedded: fields resolve as "id", "created_at"
    Name    string  `json:"name"`
    Address Address `json:"address"` // nested: resolves as "address.city"
}

v, _ := validator.New(&user)
validator.String(v, &user.Name).NotEmpty()
validator.String(v, &user.Address.City).NotEmpty().Min(2) // error field: "address.city"

Custom Validation

validator.String(v, &s.Code).Must(func(val string) bool {
    return strings.HasPrefix(val, "PRJ-")
}).WithMessage("must start with PRJ-")

WithMessage applies to the preceding rule. Directly after Each, EachValue, or EachKey it replaces the message of every error they produce.

Cross-Field & Conditional Validation

Use plain Go control flow:

v, _ := validator.New(&order)

if order.Express {
    validator.Time(v, order.ScheduledAt).NotNil().WithName("scheduled_at").WithMessage("required for express orders")
}

if order.ScheduledAt != nil {
    validator.Time(v, &order.ExpiresAt).Must(func(t time.Time) bool {
        return t.After(*order.ScheduledAt)
    }).WithMessage("must be after scheduled_at")
}

result := v.Validate()

Unstructured Objects

For unstructured data (map[string]any) such as webhooks or dynamic forms, use NewObject and declare one rule per key. Unlike New it does not return an error: any map is usable, including a nil one. A missing key validates as nil, so it is skipped unless the rule chains NotNil().

The standalone rule values come from the rule subpackage. Struct fields are typed at compile time and validated strictly, but map values arrive however the decoder produced them, so these rules coerce: numbers decoded from JSON as float64 and numeric strings both work. Error names come from the map key or element index; WithName has no effect on standalone rules.

import "github.com/Jamess-Lucass/validator-go/rule"

mv := validator.NewObject(payload)
mv.Field("email", rule.String().NotEmpty().Email())
mv.Field("age", rule.Int().Gte(18))
mv.Field("port", rule.Number[uint16]().Gt(0)) // coercion target of any width
mv.Field("address", validator.Object(func(omv *validator.ObjectValidator) {
    omv.Field("city", rule.String().NotEmpty().Min(2))
    omv.Field("country", rule.String().NotEmpty())
}).NotNil())
mv.Field("tags", validator.SliceOf(rule.String().NotEmpty()).Min(1).Max(10))
mv.Field("labels", validator.MapOf(rule.String().NotEmpty()).Max(20))

result := mv.Validate()

Object declares rules for known keys of a nested object, MapOf runs one rule over every value, and SliceOf over every element. The same rule values plug into EachValue and EachKey in struct mode. Values that don't fit the target type, like a uint64 above MaxInt64 or a fractional float for an integer rule, are rejected instead of wrapped.

Error Format

type ValidationError struct {
    Field   string `json:"field"`   // "name", "address.city", "items[0].price"
    Message string `json:"message"` // "must not be empty", "must be at least 2 characters"
}

type ValidationResult struct {
    Errors []ValidationError
}

result.IsValid() // true if no errors

License

Apache 2.0

Documentation

Overview

Package validator provides FluentValidation-style validation for Go structs and unstructured data: build a Validator with New, declare rules on fields, then call Validate. Every rule attaches the same way, as a free function taking the validator and a field pointer:

validator.String(v, &user.Name).NotEmpty().Min(2)
validator.Number(v, &user.Age).Gte(0)

Standalone rule values for unstructured data live in the rule subpackage.

A Validator is built per value and is not safe for concurrent use. Standalone rule values are read-only once built, so they can be shared across goroutines.

Example
package main

import (
	"fmt"

	validator "github.com/Jamess-Lucass/validator-go"
)

func main() {
	type User struct {
		Name  string `json:"name"`
		Email string `json:"email"`
		Age   int    `json:"age"`
	}

	user := User{Name: "J", Email: "bad", Age: -1}

	v, err := validator.New(&user)
	if err != nil {
		panic(err)
	}
	validator.String(v, &user.Name).NotEmpty().Min(2)
	validator.String(v, &user.Email).Email()
	validator.Number(v, &user.Age).Gte(0)

	result := v.Validate()

	fmt.Println(result.IsValid())
	for _, e := range result.Errors {
		fmt.Printf("%s: %s\n", e.Field, e.Message)
	}
}
Output:
false
name: must be at least 2 characters
email: must be a valid email address
age: must be greater than or equal to 0

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ArrayRule added in v1.0.0

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

ArrayRule validates a fixed-size array field. Go generics can't abstract over an array's length, so it works by reflection and takes the field as a pointer. Use Slice for slices, which keeps the element type.

func Array added in v0.3.0

func Array(v *Validator, field any) *ArrayRule

Array validates an array field by reflection; it also accepts a pointer to a slice. Pass the field address: without it the value is a copy and the name falls back to "unknown".

func (*ArrayRule) EachValue added in v1.0.0

func (r *ArrayRule) EachValue(rule Rule) *ArrayRule

EachValue validates every element against the given rule. It panics if rule is nil.

func (*ArrayRule) Length added in v1.0.0

func (r *ArrayRule) Length(min, max int) *ArrayRule

Length requires between min and max elements.

func (*ArrayRule) Max added in v1.0.0

func (r *ArrayRule) Max(n int) *ArrayRule

Max allows at most n elements.

func (*ArrayRule) Min added in v1.0.0

func (r *ArrayRule) Min(n int) *ArrayRule

Min requires at least n elements.

func (*ArrayRule) NotEmpty added in v1.0.0

func (r *ArrayRule) NotEmpty() *ArrayRule

NotEmpty fails when the array has no elements.

func (*ArrayRule) NotNil added in v1.0.0

func (r *ArrayRule) NotNil() *ArrayRule

NotNil fails when the field pointer is nil (e.g. a nil *[3]int) or points at a nil slice.

func (*ArrayRule) WithMessage added in v1.0.0

func (r *ArrayRule) WithMessage(msg string) *ArrayRule

WithMessage replaces the previous rule's error message. Directly after EachValue it instead replaces the message of every error it produces.

func (*ArrayRule) WithName added in v1.0.0

func (r *ArrayRule) WithName(name string) *ArrayRule

WithName overrides the field name used in errors.

type BoolRule added in v1.0.0

type BoolRule[T ~bool] struct {
	// contains filtered or unexported fields
}

BoolRule validates a bool field or value. Named bool types work too.

func Bool

func Bool[T ~bool](v *Validator, field *T) *BoolRule[T]

Bool validates a bool field, plain or named.

func (*BoolRule[T]) Must added in v1.0.0

func (r *BoolRule[T]) Must(fn func(T) bool) *BoolRule[T]

Must runs a custom check against the value. It panics if fn is nil.

func (*BoolRule[T]) NotEmpty added in v1.0.0

func (r *BoolRule[T]) NotEmpty() *BoolRule[T]

NotEmpty fails on false.

func (*BoolRule[T]) NotNil added in v1.0.0

func (r *BoolRule[T]) NotNil() *BoolRule[T]

NotNil fails when the field pointer or standalone value is nil.

func (*BoolRule[T]) Validate added in v1.0.0

func (r *BoolRule[T]) Validate(value any) []ValidationError

Validate implements Rule for standalone use; the value must be a bool or a named bool type.

func (*BoolRule[T]) WithMessage added in v1.0.0

func (r *BoolRule[T]) WithMessage(msg string) *BoolRule[T]

WithMessage replaces the previous rule's error message.

func (*BoolRule[T]) WithName added in v1.0.0

func (r *BoolRule[T]) WithName(name string) *BoolRule[T]

WithName overrides the field name used in errors.

type ComplexNumber added in v1.0.0

type ComplexNumber interface {
	~complex64 | ~complex128
}

ComplexNumber matches the complex types and named types based on them. Complex values are not ordered, so only presence and custom rules apply.

type ComplexRule added in v1.0.0

type ComplexRule[T ComplexNumber] struct {
	// contains filtered or unexported fields
}

ComplexRule validates a complex-number field (complex64 or complex128). Complex values aren't ordered, so only presence and custom rules apply.

func Complex added in v1.0.0

func Complex[T ComplexNumber](v *Validator, field *T) *ComplexRule[T]

Complex validates a complex-number field.

func (*ComplexRule[T]) Must added in v1.0.0

func (r *ComplexRule[T]) Must(fn func(T) bool) *ComplexRule[T]

Must runs a custom check against the value. It panics if fn is nil.

func (*ComplexRule[T]) NotEmpty added in v1.0.0

func (r *ComplexRule[T]) NotEmpty() *ComplexRule[T]

NotEmpty fails on zero.

func (*ComplexRule[T]) NotNil added in v1.0.0

func (r *ComplexRule[T]) NotNil() *ComplexRule[T]

NotNil fails when the field pointer or standalone value is nil.

func (*ComplexRule[T]) Validate added in v1.0.0

func (r *ComplexRule[T]) Validate(value any) []ValidationError

Validate implements Rule for standalone use; complex values, real numbers, and parseable strings are accepted.

func (*ComplexRule[T]) WithMessage added in v1.0.0

func (r *ComplexRule[T]) WithMessage(msg string) *ComplexRule[T]

WithMessage replaces the previous rule's error message.

func (*ComplexRule[T]) WithName added in v1.0.0

func (r *ComplexRule[T]) WithName(name string) *ComplexRule[T]

WithName overrides the field name used in errors.

type Float added in v1.0.0

type Float interface {
	~float32 | ~float64
}

Float matches the floating-point types and named types based on them.

type Integer added in v1.0.0

type Integer interface {
	~int | ~int8 | ~int16 | ~int32 | ~int64 |
		~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
}

Integer matches every built-in integer type and any named type whose underlying type is one of them (e.g. `type Age int`).

type MapRule added in v1.0.0

type MapRule[M ~map[K]V, K comparable, V any] struct {
	// contains filtered or unexported fields
}

MapRule validates a map field. Named map types (type Labels map[string]string) work too. Entries are visited in sorted key order so error output is stable from run to run.

func Map added in v1.0.0

func Map[M ~map[K]V, K comparable, V any](v *Validator, field *M) *MapRule[M, K, V]

Map validates a map field. Like Slice, it is a free function because Go methods cannot have type parameters. Pass the field address:

validator.Map(v, &d.Labels).NotEmpty().EachValue(validator.String().NotEmpty())

func MapOf added in v1.0.0

func MapOf(each Rule) *MapRule[map[string]any, string, any]

MapOf runs every value of a map through the given rule, for use with NewObject fields. It is to Map what SliceOf is to Slice.

func (*MapRule[M, K, V]) Each added in v1.0.0

func (r *MapRule[M, K, V]) Each(fn func(key K, value *V, sv *Validator)) *MapRule[M, K, V]

Each runs the callback for every entry in sorted key order. Errors raised on sv are prefixed with the entry, like "containers[web].image". The value is a copy, since map values aren't addressable. It panics if fn is nil.

func (*MapRule[M, K, V]) EachKey added in v1.0.0

func (r *MapRule[M, K, V]) EachKey(rule Rule) *MapRule[M, K, V]

EachKey validates every key against the given rule. Error messages are prefixed with "key" to tell them apart from value errors on the same entry: "labels[e]: key must be at least 2 characters". It panics if rule is nil.

func (*MapRule[M, K, V]) EachValue added in v1.0.0

func (r *MapRule[M, K, V]) EachValue(rule Rule) *MapRule[M, K, V]

EachValue validates every value against the given rule, naming errors by entry: "labels[env]: must not be empty". It panics if rule is nil.

func (*MapRule[M, K, V]) HasKey added in v1.0.0

func (r *MapRule[M, K, V]) HasKey(key K) *MapRule[M, K, V]

HasKey requires the key to be present; chain it to require several.

func (*MapRule[M, K, V]) Length added in v1.0.0

func (r *MapRule[M, K, V]) Length(min, max int) *MapRule[M, K, V]

Length requires between min and max entries.

func (*MapRule[M, K, V]) Max added in v1.0.0

func (r *MapRule[M, K, V]) Max(n int) *MapRule[M, K, V]

Max allows at most n entries.

func (*MapRule[M, K, V]) Min added in v1.0.0

func (r *MapRule[M, K, V]) Min(n int) *MapRule[M, K, V]

Min requires at least n entries.

func (*MapRule[M, K, V]) Must added in v1.0.0

func (r *MapRule[M, K, V]) Must(fn func(M) bool) *MapRule[M, K, V]

Must runs a custom check against the whole map. It panics if fn is nil.

func (*MapRule[M, K, V]) NotEmpty added in v1.0.0

func (r *MapRule[M, K, V]) NotEmpty() *MapRule[M, K, V]

NotEmpty fails when the map has no entries.

func (*MapRule[M, K, V]) NotNil added in v1.0.0

func (r *MapRule[M, K, V]) NotNil() *MapRule[M, K, V]

NotNil fails on a nil map, which is distinct from an empty one.

func (*MapRule[M, K, V]) Validate added in v1.0.0

func (r *MapRule[M, K, V]) Validate(value any) []ValidationError

Validate implements Rule for standalone use. Each callbacks run here too, since entry names come from the key rather than struct reflection.

func (*MapRule[M, K, V]) WithMessage added in v1.0.0

func (r *MapRule[M, K, V]) WithMessage(msg string) *MapRule[M, K, V]

WithMessage replaces the previous rule's error message. Directly after Each, EachValue, or EachKey it instead replaces the message of every error they produce.

func (*MapRule[M, K, V]) WithName added in v1.0.0

func (r *MapRule[M, K, V]) WithName(name string) *MapRule[M, K, V]

WithName overrides the field name used in errors.

type NumberRule added in v1.0.0

type NumberRule[T Real] struct {
	// contains filtered or unexported fields
}

NumberRule validates a field of any real (integer or float) type, including named types like `type Age int`.

func Number added in v1.0.0

func Number[T Real](v *Validator, field *T) *NumberRule[T]

Number validates a numeric field of any real type, from int and float64 to named types like type Age int. The type is inferred from the field pointer:

validator.Number(v, &s.Age).Gte(0).Lte(150)

func (*NumberRule[T]) Finite added in v1.0.0

func (r *NumberRule[T]) Finite() *NumberRule[T]

Finite fails on NaN and ±Inf; integers always pass. The comparison rules don't reject NaN on their own, so chain this where that matters.

func (*NumberRule[T]) Gt added in v1.0.0

func (r *NumberRule[T]) Gt(n T) *NumberRule[T]

Gt requires a value greater than n.

func (*NumberRule[T]) Gte added in v1.0.0

func (r *NumberRule[T]) Gte(n T) *NumberRule[T]

Gte requires a value greater than or equal to n.

func (*NumberRule[T]) Lt added in v1.0.0

func (r *NumberRule[T]) Lt(n T) *NumberRule[T]

Lt requires a value less than n.

func (*NumberRule[T]) Lte added in v1.0.0

func (r *NumberRule[T]) Lte(n T) *NumberRule[T]

Lte requires a value less than or equal to n.

func (*NumberRule[T]) MultipleOf added in v1.0.0

func (r *NumberRule[T]) MultipleOf(n T) *NumberRule[T]

MultipleOf requires the value to be a multiple of n. Exact for integers; a magnitude-relative tolerance for floats.

func (*NumberRule[T]) Must added in v1.0.0

func (r *NumberRule[T]) Must(fn func(T) bool) *NumberRule[T]

Must runs a custom check against the value. It panics if fn is nil.

func (*NumberRule[T]) Negative added in v1.0.0

func (r *NumberRule[T]) Negative() *NumberRule[T]

Negative requires a value less than zero.

func (*NumberRule[T]) Nonnegative added in v1.0.0

func (r *NumberRule[T]) Nonnegative() *NumberRule[T]

Nonnegative requires a value of zero or more.

func (*NumberRule[T]) Nonpositive added in v1.0.0

func (r *NumberRule[T]) Nonpositive() *NumberRule[T]

Nonpositive requires a value of zero or less.

func (*NumberRule[T]) NotEmpty added in v1.0.0

func (r *NumberRule[T]) NotEmpty() *NumberRule[T]

NotEmpty fails on zero.

func (*NumberRule[T]) NotNil added in v1.0.0

func (r *NumberRule[T]) NotNil() *NumberRule[T]

NotNil fails when the field pointer or standalone value is nil.

func (*NumberRule[T]) OneOf added in v1.0.0

func (r *NumberRule[T]) OneOf(values ...T) *NumberRule[T]

OneOf requires the value to be one of the given values, e.g. the members of an integer enum.

func (*NumberRule[T]) Positive added in v1.0.0

func (r *NumberRule[T]) Positive() *NumberRule[T]

Positive requires a value greater than zero.

func (*NumberRule[T]) Validate added in v1.0.0

func (r *NumberRule[T]) Validate(value any) []ValidationError

Validate implements Rule for standalone use. Any numeric kind or numeric string is coerced into T; out-of-range values are rejected, not wrapped.

func (*NumberRule[T]) WithMessage added in v1.0.0

func (r *NumberRule[T]) WithMessage(msg string) *NumberRule[T]

WithMessage replaces the previous rule's error message.

func (*NumberRule[T]) WithName added in v1.0.0

func (r *NumberRule[T]) WithName(name string) *NumberRule[T]

WithName overrides the field name used in errors.

type ObjectRule added in v1.0.0

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

ObjectRule validates a nested unstructured object within NewObject data.

func Object

func Object(fn func(*ObjectValidator)) *ObjectRule

Object declares rules for a nested object (map[string]any) inside Field:

v.Field("address", validator.Object(func(mv *validator.ObjectValidator) {
	mv.Field("city", rule.String().NotEmpty())
}))

For a typed map field on a struct (map[string]string and friends), use Map. It panics if fn is nil.

func (*ObjectRule) NotNil added in v1.0.0

func (r *ObjectRule) NotNil() *ObjectRule

NotNil fails when the key is missing or its value is nil.

func (*ObjectRule) Validate added in v1.0.0

func (r *ObjectRule) Validate(value any) []ValidationError

Validate implements Rule for standalone use; the value must be a string-keyed map.

type ObjectValidator added in v1.0.0

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

ObjectValidator validates unstructured map[string]any data, declaring one rule per key.

func NewObject added in v1.0.0

func NewObject(m map[string]any) *ObjectValidator

NewObject returns a validator for unstructured data such as a decoded JSON payload. Declare rules with Field, then call Validate.

func (*ObjectValidator) Field added in v1.0.0

func (mv *ObjectValidator) Field(key string, rule Rule)

Field declares a rule for one key of the map. It panics if rule is nil.

func (*ObjectValidator) Validate added in v1.0.0

func (mv *ObjectValidator) Validate() *ValidationResult

Validate runs every field rule and returns the collected errors.

type Real added in v1.0.0

type Real interface {
	Integer | Float
}

Real matches every ordered numeric type (integers and floats).

type Rule added in v1.0.0

type Rule interface {
	Validate(value any) []ValidationError
}

Rule is a validation check that runs against a standalone value. The constructors in the rule subpackage all return implementations.

type SliceRule added in v1.0.0

type SliceRule[S ~[]T, T any] struct {
	// contains filtered or unexported fields
}

SliceRule validates a slice field. Named slice types (type Tags []string) work too.

func Slice added in v1.0.0

func Slice[S ~[]T, T any](v *Validator, field *S) *SliceRule[S, T]

Slice validates a slice field. Like every rule it is a free function, since Go methods cannot have their own type parameters. Pass the field address:

validator.Slice(v, &s.Tags).NotEmpty().EachValue(rule.String().NotEmpty())

func SliceOf added in v1.0.0

func SliceOf(each Rule) *SliceRule[[]any, any]

SliceOf runs each element of a slice value through the given rule, for use with NewObject fields.

func (*SliceRule[S, T]) Each added in v1.0.0

func (r *SliceRule[S, T]) Each(fn func(item *T, sv *Validator)) *SliceRule[S, T]

Each runs the callback for every element with a sub-validator; errors are prefixed with the index, like "items[2].name". It panics if fn is nil.

func (*SliceRule[S, T]) EachValue added in v1.0.0

func (r *SliceRule[S, T]) EachValue(rule Rule) *SliceRule[S, T]

EachValue checks every element against the rule, naming errors by index. It panics if rule is nil.

func (*SliceRule[S, T]) Length added in v1.0.0

func (r *SliceRule[S, T]) Length(min, max int) *SliceRule[S, T]

Length requires between min and max elements.

func (*SliceRule[S, T]) Max added in v1.0.0

func (r *SliceRule[S, T]) Max(n int) *SliceRule[S, T]

Max allows at most n elements.

func (*SliceRule[S, T]) Min added in v1.0.0

func (r *SliceRule[S, T]) Min(n int) *SliceRule[S, T]

Min requires at least n elements.

func (*SliceRule[S, T]) Must added in v1.0.0

func (r *SliceRule[S, T]) Must(fn func(S) bool) *SliceRule[S, T]

Must runs a custom check against the whole slice. It panics if fn is nil.

func (*SliceRule[S, T]) NotEmpty added in v1.0.0

func (r *SliceRule[S, T]) NotEmpty() *SliceRule[S, T]

NotEmpty fails when the slice has no elements.

func (*SliceRule[S, T]) NotNil added in v1.0.0

func (r *SliceRule[S, T]) NotNil() *SliceRule[S, T]

NotNil fails on a nil slice, which is distinct from an empty one.

func (*SliceRule[S, T]) Validate added in v1.0.0

func (r *SliceRule[S, T]) Validate(value any) []ValidationError

Validate implements Rule for standalone use. Each callbacks only run in struct mode, where there are field pointers to resolve names against.

func (*SliceRule[S, T]) WithMessage added in v1.0.0

func (r *SliceRule[S, T]) WithMessage(msg string) *SliceRule[S, T]

WithMessage replaces the previous rule's error message. Directly after Each or EachValue it instead replaces the message of every error they produce.

func (*SliceRule[S, T]) WithName added in v1.0.0

func (r *SliceRule[S, T]) WithName(name string) *SliceRule[S, T]

WithName overrides the field name used in errors.

type StringRule added in v1.0.0

type StringRule[T ~string] struct {
	// contains filtered or unexported fields
}

StringRule validates a string field or value. Named string types (type ID string) work too.

func String

func String[T ~string](v *Validator, field *T) *StringRule[T]

String validates a string field, plain or named:

validator.String(v, &s.Name).NotEmpty().Min(2)

func (*StringRule[T]) Email added in v1.0.0

func (r *StringRule[T]) Email() *StringRule[T]

Email requires a valid email address.

func (*StringRule[T]) EndsWith added in v1.0.0

func (r *StringRule[T]) EndsWith(suffix string) *StringRule[T]

EndsWith requires the given suffix.

func (*StringRule[T]) Includes added in v1.0.0

func (r *StringRule[T]) Includes(substr string) *StringRule[T]

Includes requires the substring to be present.

func (*StringRule[T]) Length added in v1.0.0

func (r *StringRule[T]) Length(min, max int) *StringRule[T]

Length requires between min and max characters, counting runes.

func (*StringRule[T]) Matches added in v1.0.0

func (r *StringRule[T]) Matches(pattern string) *StringRule[T]

Matches requires the value to match the regular expression. The pattern is compiled once when the rule is declared; like regexp.MustCompile, an invalid pattern panics.

func (*StringRule[T]) Max added in v1.0.0

func (r *StringRule[T]) Max(n int) *StringRule[T]

Max allows at most n characters, counting runes rather than bytes.

func (*StringRule[T]) Min added in v1.0.0

func (r *StringRule[T]) Min(n int) *StringRule[T]

Min requires at least n characters, counting runes rather than bytes.

func (*StringRule[T]) Must added in v1.0.0

func (r *StringRule[T]) Must(fn func(T) bool) *StringRule[T]

Must runs a custom check against the value. It panics if fn is nil.

func (*StringRule[T]) NotEmpty added in v1.0.0

func (r *StringRule[T]) NotEmpty() *StringRule[T]

NotEmpty fails on "".

func (*StringRule[T]) NotNil added in v1.0.0

func (r *StringRule[T]) NotNil() *StringRule[T]

NotNil fails when the field pointer or standalone value is nil.

func (*StringRule[T]) OneOf added in v1.0.0

func (r *StringRule[T]) OneOf(values ...T) *StringRule[T]

OneOf requires the value to be one of the given values, e.g. the members of a string enum.

func (*StringRule[T]) StartsWith added in v1.0.0

func (r *StringRule[T]) StartsWith(prefix string) *StringRule[T]

StartsWith requires the given prefix.

func (*StringRule[T]) URL added in v1.0.0

func (r *StringRule[T]) URL() *StringRule[T]

URL requires an absolute URL with a scheme and host.

func (*StringRule[T]) Validate added in v1.0.0

func (r *StringRule[T]) Validate(value any) []ValidationError

Validate implements Rule for standalone use; the value must be a string or a named string type.

func (*StringRule[T]) WithMessage added in v1.0.0

func (r *StringRule[T]) WithMessage(msg string) *StringRule[T]

WithMessage replaces the previous rule's error message.

func (*StringRule[T]) WithName added in v1.0.0

func (r *StringRule[T]) WithName(name string) *StringRule[T]

WithName overrides the field name used in errors.

type TimeRule added in v1.0.0

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

TimeRule validates a time.Time field or value.

func Time added in v0.5.0

func Time(v *Validator, field *time.Time) *TimeRule

Time validates a time.Time field.

func (*TimeRule) After added in v1.0.0

func (r *TimeRule) After(t time.Time) *TimeRule

After requires the value to be after t.

func (*TimeRule) Before added in v1.0.0

func (r *TimeRule) Before(t time.Time) *TimeRule

Before requires the value to be before t.

func (*TimeRule) Must added in v1.0.0

func (r *TimeRule) Must(fn func(time.Time) bool) *TimeRule

Must runs a custom check against the value. It panics if fn is nil.

func (*TimeRule) NotEmpty added in v1.0.0

func (r *TimeRule) NotEmpty() *TimeRule

NotEmpty fails on the zero time.

func (*TimeRule) NotNil added in v1.0.0

func (r *TimeRule) NotNil() *TimeRule

NotNil fails when the field pointer or standalone value is nil.

func (*TimeRule) Validate added in v1.0.0

func (r *TimeRule) Validate(value any) []ValidationError

Validate implements Rule for standalone use; the value must be a time.Time or an RFC3339 string.

func (*TimeRule) WithMessage added in v1.0.0

func (r *TimeRule) WithMessage(msg string) *TimeRule

WithMessage replaces the previous rule's error message.

func (*TimeRule) WithName added in v1.0.0

func (r *TimeRule) WithName(name string) *TimeRule

WithName overrides the field name used in errors.

type UUIDRule added in v1.0.0

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

UUIDRule validates a github.com/google/uuid value.

func UUID added in v0.2.0

func UUID(v *Validator, field *uuid.UUID) *UUIDRule

UUID validates a uuid.UUID field.

func (*UUIDRule) Must added in v1.0.0

func (r *UUIDRule) Must(fn func(uuid.UUID) bool) *UUIDRule

Must runs a custom check against the value. It panics if fn is nil.

func (*UUIDRule) NotEmpty added in v1.0.0

func (r *UUIDRule) NotEmpty() *UUIDRule

NotEmpty fails on the nil UUID (all zeros).

func (*UUIDRule) NotNil added in v1.0.0

func (r *UUIDRule) NotNil() *UUIDRule

NotNil fails when the field pointer or standalone value is nil.

func (*UUIDRule) Validate added in v1.0.0

func (r *UUIDRule) Validate(value any) []ValidationError

Validate implements Rule for standalone use; the value must be a uuid.UUID, a [16]byte, or a parseable string.

func (*UUIDRule) WithMessage added in v1.0.0

func (r *UUIDRule) WithMessage(msg string) *UUIDRule

WithMessage replaces the previous rule's error message.

func (*UUIDRule) WithName added in v1.0.0

func (r *UUIDRule) WithName(name string) *UUIDRule

WithName overrides the field name used in errors.

type ValidationError

type ValidationError struct {
	Field   string `json:"field"`
	Message string `json:"message"`
}

ValidationError is a single failed check: which field, and why.

func (ValidationError) Error

func (e ValidationError) Error() string

Error formats the error as "field: message".

type ValidationResult

type ValidationResult struct {
	Errors []ValidationError `json:"errors"`
}

ValidationResult holds every error collected by a Validate call.

func (*ValidationResult) IsValid

func (r *ValidationResult) IsValid() bool

IsValid reports whether no errors were found.

type Validator

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

Validator collects rules for one struct and runs them on Validate.

func New added in v1.0.0

func New(structPtr any) (*Validator, error)

New returns a Validator for structPtr, which must be a non-nil pointer to a struct.

func (*Validator) Validate added in v1.0.0

func (v *Validator) Validate() *ValidationResult

Validate runs every rule against the struct's current values.

Directories

Path Synopsis
Package rule provides standalone rule values: reusable validation chains that aren't bound to a struct field.
Package rule provides standalone rule values: reusable validation chains that aren't bound to a struct field.

Jump to

Keyboard shortcuts

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