validation

package module
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: Dec 12, 2025 License: MIT Imports: 8 Imported by: 1

Documentation

Overview

Package validation provides a type-safe validation framework using Go generics.

This package offers compile-time type safety for validators, ensuring that validators can only be applied to compatible types. For example, a MinLength validator can only be used on strings, not integers.

Example usage:

func (input CreateUserInput) Validate() error {
    return errors.Join(
        validation.Validate(input.Email,
            validation.Required[string](),
            validation.IsEmail(),
        ),
        validation.Validate(input.Age,
            validation.Required[int](),
            validation.Range(18, 120),
        ),
    )
}
Example

Example demonstrates basic validation usage

package main

import (
	"errors"
	"fmt"

	"github.com/quantumcycle/protego/validation"
)

func main() {
	type CreateUser struct {
		Email    string
		Username string
		Age      int
	}

	input := CreateUser{
		Email:    "test@example.com",
		Username: "john123",
		Age:      25,
	}

	err := errors.Join(
		validation.Validate(input.Email,
			validation.Required[string](),
			validation.Contains("@"),
		),
		validation.Validate(input.Username,
			validation.Required[string](),
			validation.Length(3, 20),
			validation.MatchesPattern(`^[a-zA-Z0-9]+$`),
		),
		validation.Validate(input.Age,
			validation.Required[int](),
			validation.Range(18, 120),
		),
	)

	if err != nil {
		fmt.Println("Validation failed:", err)
	} else {
		fmt.Println("Validation passed")
	}
}
Output:

Validation passed
Example (AnyMapValidation)

Example_anyMapValidation demonstrates validating map[string]any (JSON-style data)

package main

import (
	"fmt"

	"github.com/quantumcycle/protego/validation"
)

func main() {
	data := map[string]any{
		"name":   "John Doe",
		"age":    30,
		"active": true,
	}

	err := validation.ValidateAnyMap(
		data,
		true, // allow extra keys
		validation.MapKey("name", true, validation.StringValidator(validation.Required[string]())),
		validation.MapKey("age", true, validation.IntValidator(validation.Range(0, 120))),
		validation.MapKey("active", false, validation.BoolValidator(validation.Custom(func(v bool) error {
			return nil // Any bool value is fine
		}))),
	)

	if err != nil {
		fmt.Println("Validation failed:", err)
	} else {
		fmt.Println("Validation passed")
	}
}
Output:

Validation passed
Example (ComposedValidators)

Example_composedValidators demonstrates using And, Or, and Not

package main

import (
	"errors"
	"fmt"

	"github.com/quantumcycle/protego/validation"
)

func main() {
	// Complex password validator: min 8 chars, has uppercase, has number
	passwordValidator := validation.And(
		validation.MinLength(8),
		validation.MatchesPattern(`[A-Z]`), // has uppercase
		validation.MatchesPattern(`[0-9]`), // has number
	)

	// Email or phone validator
	contactValidator := validation.Or(
		validation.Contains("@"),
		validation.MatchesPattern(`^\+\d{10,}$`),
	)

	password := "SecureP@ss123"
	contact := "test@example.com"

	err := errors.Join(
		validation.Validate(password, passwordValidator),
		validation.Validate(contact, contactValidator),
	)

	if err != nil {
		fmt.Println("Validation failed:", err)
	} else {
		fmt.Println("Validation passed")
	}
}
Output:

Validation passed
Example (ConditionalValidation)

ExampleConditionalValidation demonstrates conditional validation

package main

import (
	"fmt"

	"github.com/quantumcycle/protego/validation"
)

func main() {
	type Order struct {
		RequiresShipping bool
		ShippingAddress  string
	}

	input := Order{
		RequiresShipping: false,
		ShippingAddress:  "", // Empty, but that's okay since RequiresShipping is false
	}

	err := validation.Validate(input.ShippingAddress,
		validation.When(
			input.RequiresShipping,
			validation.Required[string](),
		),
	)

	if err != nil {
		fmt.Println("Validation failed:", err)
	} else {
		fmt.Println("Validation passed")
	}
}
Output:

Validation passed
Example (CustomValidator)

ExampleCustomValidator demonstrates creating custom validators

package main

import (
	"fmt"

	"github.com/quantumcycle/protego/validation"
)

func main() {
	// Define a custom validator
	IsPositiveEven := func() validation.Validator[int] {
		return func(v int) error {
			if v <= 0 {
				return fmt.Errorf("must be positive")
			}
			if v%2 != 0 {
				return fmt.Errorf("must be even")
			}
			return nil
		}
	}

	err := validation.Validate(4, IsPositiveEven())

	if err != nil {
		fmt.Println("Validation failed:", err)
	} else {
		fmt.Println("Validation passed")
	}
}
Output:

Validation passed
Example (DateValidation)

Example_dateValidation demonstrates date and time validation

package main

import (
	"errors"
	"fmt"

	"github.com/quantumcycle/protego/validation"
)

func main() {
	// RFC3339 datetime
	timestamp := "2024-12-31T23:59:59Z"

	// ISO8601 date only
	birthDate := "1990-05-15"

	err := errors.Join(
		validation.Validate(timestamp, validation.IsRFC3339DateTime()),
		validation.Validate(birthDate, validation.IsISO8601Date()),
	)

	if err != nil {
		fmt.Println("Validation failed:", err)
	} else {
		fmt.Println("Validation passed")
	}
}
Output:

Validation passed
Example (MapValidation)

Example_mapValidation demonstrates validating map[string]string

package main

import (
	"fmt"

	"github.com/quantumcycle/protego/validation"
)

func main() {
	config := map[string]string{
		"host": "localhost",
		"port": "8080",
	}

	err := validation.ValidateStringMap(
		config,
		true, // allow extra keys
		validation.MapKey("host", true, validation.Required[string]()),
		validation.MapKey("port", true, validation.IsInt()),
	)

	if err != nil {
		fmt.Println("Validation failed:", err)
	} else {
		fmt.Println("Validation passed")
	}
}
Output:

Validation passed
Example (NestedValidation)

Example_nestedValidation demonstrates validating nested structs

package main

import (
	"errors"
	"fmt"

	"github.com/quantumcycle/protego/validation"
)

func main() {
	type Address struct {
		Street string
		City   string
	}

	type User struct {
		Name    string
		Address Address
	}

	// Address implements Validatable interface
	validateAddress := func(a Address) error {
		return errors.Join(
			validation.Validate(a.Street, validation.Required[string]()),
			validation.Validate(a.City, validation.Required[string]()),
		)
	}

	user := User{
		Name: "John Doe",
		Address: Address{
			Street: "123 Main St",
			City:   "Springfield",
		},
	}

	err := errors.Join(
		validation.Validate(user.Name, validation.Required[string]()),
		validateAddress(user.Address),
	)

	if err != nil {
		fmt.Println("Validation failed:", err)
	} else {
		fmt.Println("Validation passed")
	}
}
Output:

Validation passed
Example (OptionalFields)

ExampleOptionalFields demonstrates validation of optional pointer fields

package main

import (
	"errors"
	"fmt"

	"github.com/quantumcycle/protego/validation"
)

func main() {
	type UpdateUser struct {
		Email *string
		Age   *int
	}

	email := "test@example.com"
	age := 25
	input := UpdateUser{
		Email: &email,
		Age:   &age,
	}

	err := errors.Join(
		validation.Validate(input.Email,
			validation.NilOr(validation.Contains("@")),
		),
		validation.Validate(input.Age,
			validation.NilOr(validation.Range(0, 120)),
		),
	)

	if err != nil {
		fmt.Println("Validation failed:", err)
	} else {
		fmt.Println("Validation passed")
	}
}
Output:

Validation passed
Example (SliceValidation)

ExampleSliceValidation demonstrates validation of slices

package main

import (
	"fmt"

	"github.com/quantumcycle/protego/validation"
)

func main() {
	emails := []string{"test1@example.com", "test2@example.com", "test3@example.com"}

	err := validation.Validate(emails,
		validation.NotEmpty[string](),
		validation.MaxItems[string](10),
		validation.Each(validation.Contains("@")),
	)

	if err != nil {
		fmt.Println("Validation failed:", err)
	} else {
		fmt.Println("Validation passed")
	}
}
Output:

Validation passed

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsValidationError

func IsValidationError(err error) bool

IsValidationError checks if an error is a validation Error or wraps one. This allows users to detect if an error came from Protego validation.

Example:

if validation.IsValidationError(err) {
    // Handle validation error
}

func NewValidationError

func NewValidationError(msg string) error

NewValidationError creates a new validation Error with the given message. This should be used for creating new validation errors in validators.

Example:

return validation.NewValidationError("must be at least 3 characters")

func Validate

func Validate[T any](value T, validators ...Validator[T]) error

Validate applies multiple validators to a value and returns the first error encountered. All validators are applied in order, and validation stops at the first failure.

Example:

err := validation.Validate(name,
    validation.Required[string](),
    validation.MinLength(3),
    validation.MaxLength(50),
)

func ValidateAnyMap

func ValidateAnyMap(m map[string]any, allowExtra bool, rules ...MapKeyRule[any]) error

ValidateAnyMap validates a map[string]any (JSON-style map) with the specified rules. If allowExtra is false, any keys not defined in rules will cause an error.

Example:

err := validation.ValidateAnyMap(
    jsonData,
    true, // allow extra keys
    validation.MapKey("name", true, validation.StringValidator(validation.Required[string]())),
    validation.MapKey("age", false, validation.AnyValidator(func(v any) error {
        age, ok := v.(float64)
        if !ok { return fmt.Errorf("must be a number") }
        return validation.Validate(int(age), validation.Range(0, 120))
    })),
)

func ValidateNested

func ValidateNested[T any](value T) error

ValidateNested checks if the value implements Validatable and calls its Validate() method. If the value doesn't implement Validatable, it returns nil (no validation performed).

Example:

type Address struct { ... }
func (a Address) Validate() error { ... }

type User struct {
    Name    string
    Address Address
}

func (u User) Validate() error {
    return errors.Join(
        validation.Validate(u.Name, validation.Required[string]()),
        validation.ValidateNested(u.Address), // Calls Address.Validate()
    )
}

func ValidateStringMap

func ValidateStringMap(m map[string]string, allowExtra bool, rules ...MapKeyRule[string]) error

ValidateStringMap validates a map[string]string with the specified rules. If allowExtra is false, any keys not defined in rules will cause an error.

Example:

err := validation.ValidateStringMap(
    config,
    true, // allow extra keys
    validation.MapKey("host", true, validation.Required[string]()),
    validation.MapKey("port", true, validation.IsInt()),
)

func WrapError

func WrapError(err error) error

WrapError wraps an existing error as a validation Error. If the error is already a validation Error, it returns it as-is. This is useful for wrapping errors from external libraries (like go-playground/validator).

Example:

return validation.WrapError(externalLibraryError)

Types

type Error

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

Error represents an error that occurred during validation. It wraps validation errors to make them identifiable as Protego errors.

func (*Error) Error

func (e *Error) Error() string

Error returns the error message.

func (*Error) Is

func (e *Error) Is(target error) bool

Is allows Error to work with errors.Is().

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap returns the underlying error, if any.

type MapKeyRule

type MapKeyRule[V any] struct {
	// contains filtered or unexported fields
}

MapKeyRule represents a validation rule for a specific key in a map.

func MapKey

func MapKey[V any](key string, required bool, validators ...Validator[V]) MapKeyRule[V]

MapKey creates a validation rule for a map key. If required is true, the key must exist in the map.

Example:

validation.MapKey("name", true, validation.Required[string](), validation.MinLength(3))

type Validatable

type Validatable interface {
	Validate() error
}

Validatable is an interface for types that have a Validate() method. This is useful for nested struct validation.

type Validator

type Validator[T any] func(T) error

Validator is a generic validation function that validates a value of type T. It returns an error if validation fails, or nil if the value is valid.

func And

func And[T any](validators ...Validator[T]) Validator[T]

And combines multiple validators - all must pass for validation to succeed. This is the default behavior of Validate, but And can be useful for composition.

Example:

passwordValidator := validation.And(
    validation.MinLength(8),
    validation.MatchesPattern(`[A-Z]`), // must have uppercase
    validation.MatchesPattern(`[0-9]`), // must have number
)
validation.Validate(password, passwordValidator)

func BoolValidator

func BoolValidator(validator Validator[bool]) Validator[any]

BoolValidator converts a bool validator to work with any type by first asserting it's a boolean. This is useful for ValidateAnyMap when you know a value should be a bool.

Example:

validation.MapKey("active", true, validation.BoolValidator(validation.Custom(func(v bool) error {
    if !v { return fmt.Errorf("must be active") }
    return nil
})))

func Contains

func Contains(substring string) Validator[string]

Contains validates that a string contains the specified substring.

Example:

validation.Validate(text, validation.Contains("important"))

func Custom

func Custom[T any](fn func(T) error) Validator[T]

Custom creates a custom validator from a function. This is useful for inline validators or wrapping complex validation logic.

Example:

validation.Validate(username,
    validation.Custom(func(v string) error {
        if containsProfanity(v) {
            return fmt.Errorf("contains inappropriate content")
        }
        return nil
    }),
)

func Each

func Each[T any](elementValidator Validator[T]) Validator[[]T]

Each validates each element in a slice using the provided element validator. All errors are collected and returned as a joined error.

Example:

validation.Validate(emails, validation.Each(validation.IsEmail()))
validation.Validate(ages, validation.Each(validation.Range(0, 120)))

func EndsWith

func EndsWith(suffix string) Validator[string]

EndsWith validates that a string ends with the specified suffix.

Example:

validation.Validate(filename, validation.EndsWith(".json"))

func FloatValidator

func FloatValidator(validator Validator[float64]) Validator[any]

FloatValidator converts a float64 validator to work with any type by first asserting it's a number. This is useful for ValidateAnyMap when you know a value should be a float.

Example:

validation.MapKey("price", true, validation.FloatValidator(validation.Min(0.0)))

func GreaterThan

func GreaterThan[T constraints.Ordered](threshold T) Validator[T]

GreaterThan validates that a value is strictly greater than the specified value.

Example:

validation.Validate(count, validation.GreaterThan(0))

func In

func In[T comparable](caseInsensitive bool, allowed ...T) Validator[T]

In validates that a value is in the allowed list. If caseInsensitive is true, string values are compared case-insensitively.

Example:

validation.Validate(status, validation.In(false, "ACTIVE", "INACTIVE", "PENDING"))
validation.Validate(mode, validation.In(true, "single", "multiple")) // case-insensitive

func InSlice

func InSlice[T comparable](caseInsensitive bool, allowed []T) Validator[T]

InSlice validates that a value is in the allowed slice. This is similar to In but takes a slice instead of variadic arguments.

Example:

allowedCurrencies := []string{"USD", "EUR", "GBP"}
validation.Validate(currency, validation.InSlice(true, allowedCurrencies))

func IntValidator

func IntValidator(validator Validator[int]) Validator[any]

IntValidator converts an int validator to work with any type by first asserting it's a number. This is useful for ValidateAnyMap when you know a value should be an int.

Example:

validation.MapKey("age", true, validation.IntValidator(validation.Range(0, 120)))

func IsDateAfter

func IsDateAfter(afterDate string) Validator[string]

IsDateAfter validates that a string represents a date after the specified date. Both dates are parsed as RFC3339 format.

Example:

validation.Validate(endDate, validation.IsDateAfter("2024-01-01T00:00:00Z"))

func IsDateAfterFormat

func IsDateAfterFormat(afterDate, layout string) Validator[string]

IsDateAfterFormat validates that a string represents a date after the specified date. Both dates are parsed using the specified layout.

Example:

validation.Validate(endDate, validation.IsDateAfterFormat("2024-01-01", "2006-01-02"))

func IsDateBefore

func IsDateBefore(beforeDate string) Validator[string]

IsDateBefore validates that a string represents a date before the specified date. Both dates are parsed as RFC3339 format.

Example:

validation.Validate(startDate, validation.IsDateBefore("2024-12-31T23:59:59Z"))

func IsDateBeforeFormat

func IsDateBeforeFormat(beforeDate, layout string) Validator[string]

IsDateBeforeFormat validates that a string represents a date before the specified date. Both dates are parsed using the specified layout.

Example:

validation.Validate(startDate, validation.IsDateBeforeFormat("2024-12-31", "2006-01-02"))

func IsDateFormat

func IsDateFormat(layout string) Validator[string]

IsDateFormat validates that a string matches the specified date format. The layout uses Go's time format layout (reference time: Mon Jan 2 15:04:05 MST 2006).

Example:

validation.Validate(date, validation.IsDateFormat("2006-01-02 15:04:05"))

func IsFutureDate

func IsFutureDate() Validator[string]

IsFutureDate validates that a string represents a date in the future. The date is parsed as RFC3339 format.

Example:

validation.Validate(expiryDate, validation.IsFutureDate())

func IsFutureDateFormat

func IsFutureDateFormat(layout string) Validator[string]

IsFutureDateFormat validates that a string represents a date in the future. The date is parsed using the specified layout.

Example:

validation.Validate(expiryDate, validation.IsFutureDateFormat("2006-01-02"))

func IsFutureTime

func IsFutureTime() Validator[time.Time]

IsFutureTime validates that a time.Time is in the future.

Example:

validation.Validate(expiryTime, validation.IsFutureTime())

func IsISO8601Date

func IsISO8601Date() Validator[string]

IsISO8601Date validates that a string is a valid ISO8601 date in YYYY-MM-DD format.

Example:

validation.Validate(birthDate, validation.IsISO8601Date())

func IsInt

func IsInt() Validator[string]

IsInt validates that a string represents a valid integer.

Example:

validation.Validate(idString, validation.IsInt())

func IsPastDate

func IsPastDate() Validator[string]

IsPastDate validates that a string represents a date in the past. The date is parsed as RFC3339 format.

Example:

validation.Validate(birthDate, validation.IsPastDate())

func IsPastDateFormat

func IsPastDateFormat(layout string) Validator[string]

IsPastDateFormat validates that a string represents a date in the past. The date is parsed using the specified layout.

Example:

validation.Validate(birthDate, validation.IsPastDateFormat("2006-01-02"))

func IsPastTime

func IsPastTime() Validator[time.Time]

IsPastTime validates that a time.Time is in the past.

Example:

validation.Validate(birthTime, validation.IsPastTime())

func IsRFC3339DateTime

func IsRFC3339DateTime() Validator[string]

IsRFC3339DateTime validates that a string is a valid RFC3339 date-time. RFC3339 is the standard format used by JSON and most APIs (e.g., "2006-01-02T15:04:05Z07:00").

Example:

validation.Validate(timestamp, validation.IsRFC3339DateTime())

func IsTimeAfter

func IsTimeAfter(after time.Time) Validator[time.Time]

IsTimeAfter validates that a time.Time is after the specified time.

Example:

validation.Validate(endTime, validation.IsTimeAfter(startTime))

func IsTimeBefore

func IsTimeBefore(before time.Time) Validator[time.Time]

IsTimeBefore validates that a time.Time is before the specified time.

Example:

validation.Validate(startTime, validation.IsTimeBefore(endTime))

func Length

func Length(minimum, maximum int) Validator[string]

Length validates that a string length is between minimum and maximum (inclusive).

Example:

validation.Validate(username, validation.Length(3, 20))

func LessThan

func LessThan[T constraints.Ordered](threshold T) Validator[T]

LessThan validates that a value is strictly less than the specified value.

Example:

validation.Validate(percentage, validation.LessThan(100.0))

func MatchesPattern

func MatchesPattern(pattern string) Validator[string]

MatchesPattern validates that a string matches the given regular expression pattern.

Example:

validation.Validate(code, validation.MatchesPattern(`^[A-Z]{3}-\d{4}$`))

func Max

func Max[T constraints.Ordered](maximum T) Validator[T]

Max validates that a value is less than or equal to the specified maximum.

Example:

validation.Validate(age, validation.Max(120))
validation.Validate(discount, validation.Max(1.0))

func MaxItems

func MaxItems[T any](maximum int) Validator[[]T]

MaxItems validates that a slice has at most the specified maximum number of items.

Example:

validation.Validate(tags, validation.MaxItems[string](10))

func MaxLength

func MaxLength(maximum int) Validator[string]

MaxLength validates that a string has at most the specified maximum length.

Example:

validation.Validate(name, validation.MaxLength(50))

func Min

func Min[T constraints.Ordered](minimum T) Validator[T]

Min validates that a value is greater than or equal to the specified minimum.

Example:

validation.Validate(age, validation.Min(18))
validation.Validate(price, validation.Min(0.0))

func MinItems

func MinItems[T any](minimum int) Validator[[]T]

MinItems validates that a slice has at least the specified minimum number of items.

Example:

validation.Validate(tags, validation.MinItems[string](1))

func MinLength

func MinLength(minimum int) Validator[string]

MinLength validates that a string has at least the specified minimum length.

Example:

validation.Validate(name, validation.MinLength(3))

func MultipleOf

func MultipleOf[T constraints.Integer](divisor T) Validator[T]

MultipleOf validates that a numeric value is a multiple of the specified divisor.

Example:

validation.Validate(quantity, validation.MultipleOf(5))

func Negative

func Negative[T constraints.Ordered]() Validator[T]

Negative validates that a numeric value is less than zero.

Example:

validation.Validate(debit, validation.Negative[float64]())

func Nested

func Nested[T Validatable]() Validator[T]

Nested returns a validator that calls the Validate() method on nested structs. This is a wrapper around ValidateNested for use with the Validate function.

Example:

validation.Validate(user.Address, validation.Nested[Address]())

func NilOr

func NilOr[T any](validator Validator[T]) Validator[*T]

NilOr wraps a validator to make it work with optional (pointer) fields. If the pointer is nil, validation passes. If not nil, the wrapped validator is applied.

Example:

type UpdateUserInput struct {
    Email    *string
    Age      *int
    Priority *int
}

func (input UpdateUserInput) Validate() error {
    return errors.Join(
        validation.Validate(input.Email,
            validation.NilOr(validation.IsEmail()),
        ),
        validation.Validate(input.Age,
            validation.NilOr(validation.Range(0, 120)),
        ),
        validation.Validate(input.Priority,
            validation.NilOr(validation.In(false, 1, 2, 3)),
        ),
    )
}

func NilOrNotEmpty

func NilOrNotEmpty() Validator[*string]

NilOrNotEmpty validates that a pointer to string is either nil or not empty. This is useful for optional fields that, if provided, must not be empty.

Example:

type UpdateUserInput struct {
    Name *string
}

validation.Validate(input.Name, validation.NilOrNotEmpty())

func NonNegative

func NonNegative[T constraints.Ordered]() Validator[T]

NonNegative validates that a numeric value is greater than or equal to zero.

Example:

validation.Validate(count, validation.NonNegative[int]())

func Not

func Not[T any](validator Validator[T]) Validator[T]

Not inverts a validator - it passes if the validator fails, and vice versa.

Example:

validation.Validate(username,
    validation.Not(validation.In(false, "admin", "root")), // must NOT be admin or root
)

func NotEmpty

func NotEmpty[T any]() Validator[[]T]

NotEmpty validates that a slice is not empty.

Example:

validation.Validate(tags, validation.NotEmpty[string]())

func NotIn

func NotIn[T comparable](caseInsensitive bool, forbidden ...T) Validator[T]

NotIn validates that a value is NOT in the forbidden list.

Example:

validation.Validate(username, validation.NotIn(false, "admin", "root", "system"))

func NotNil

func NotNil[T any]() Validator[*T]

NotNil validates that a pointer is not nil.

Example:

validation.Validate(input.RequiredField, validation.NotNil[string]())

func OptionalWith

func OptionalWith[T any](validators ...Validator[T]) Validator[*T]

OptionalWith validates an optional field with multiple validators if it's not nil. This is a convenience function that combines NilOr with multiple validators.

Example:

validation.Validate(input.Email,
    validation.OptionalWith(
        validation.IsEmail(),
        validation.MinLength(5),
    ),
)

func Or

func Or[T any](validators ...Validator[T]) Validator[T]

Or combines multiple validators - at least one must pass for validation to succeed. If all validators fail, a combined error is returned.

Example:

// Accept either email or phone number
validation.Validate(contact,
    validation.Or(
        validation.IsEmail(),
        validation.MatchesPattern(`^\+\d{10,}$`), // phone pattern
    ),
)

func Positive

func Positive[T constraints.Ordered]() Validator[T]

Positive validates that a numeric value is greater than zero.

Example:

validation.Validate(amount, validation.Positive[int]())
validation.Validate(price, validation.Positive[float64]())

func Range

func Range[T constraints.Ordered](minimum, maximum T) Validator[T]

Range validates that a value is between minimum and maximum (inclusive).

Example:

validation.Validate(age, validation.Range(18, 120))
validation.Validate(rating, validation.Range(1, 5))

func Required

func Required[T comparable]() Validator[T]

Required validates that a value is not the zero value for its type. For strings, this means not empty. For numbers, this means not zero. For pointers, this means not nil.

Example:

validation.Validate(name, validation.Required[string]())
validation.Validate(age, validation.Required[int]())

func RequiredIf

func RequiredIf[T comparable](condition bool) Validator[T]

RequiredIf validates that a value is not the zero value if the condition is true. If the condition is false, validation passes regardless of the value.

Example:

validation.Validate(input.ShippingAddress,
    validation.RequiredIf[string](input.RequiresShipping),
)

func StartsWith

func StartsWith(prefix string) Validator[string]

StartsWith validates that a string starts with the specified prefix.

Example:

validation.Validate(packageName, validation.StartsWith("com."))

func StringValidator

func StringValidator(validator Validator[string]) Validator[any]

StringValidator converts a string validator to work with any type by first asserting it's a string. This is useful for ValidateAnyMap when you know a value should be a string.

Example:

validation.MapKey("email", true, validation.StringValidator(validation.IsEmail()))

func UniqueItems

func UniqueItems[T comparable]() Validator[[]T]

UniqueItems validates that all items in a slice are unique.

Example:

validation.Validate(ids, validation.UniqueItems[string]())

func Unless

func Unless[T any](condition bool, validator Validator[T]) Validator[T]

Unless applies a validator only if the condition is false. This is the opposite of When.

Example:

validation.Validate(input.Reason,
    validation.Unless(
        input.IsApproved,
        validation.Required[string](), // reason required if not approved
    ),
)

func When

func When[T any](condition bool, validator Validator[T]) Validator[T]

When applies a validator only if the condition is true. This is useful for conditional validation.

Example:

validation.Validate(input.ShippingAddress,
    validation.When(
        input.RequiresShipping,
        validation.Required[string](),
    ),
)

func WithMessage

func WithMessage[T any](validator Validator[T], message string) Validator[T]

WithMessage wraps a validator and replaces its error message with a custom message. This is useful when you want to provide more specific or user-friendly error messages.

Example:

validation.Validate(input.Count,
    validation.WithMessage(
        validation.Required[int](),
        "count cannot be zero",
    ),
)

Jump to

Keyboard shortcuts

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