validation

package
v2.1.11 Latest Latest
Warning

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

Go to latest
Published: Jan 16, 2026 License: Apache-2.0 Imports: 6 Imported by: 0

Documentation

Overview

Package validation provides functional validation types and operations for the codec system.

This package implements a validation monad that accumulates errors during validation operations, making it ideal for form validation, data parsing, and other scenarios where you want to collect all validation errors rather than failing on the first error.

Core Concepts

Validation[A]: Represents the result of a validation operation as Either[Errors, A]:

  • Left(Errors): Validation failed with one or more errors
  • Right(A): Successfully validated value of type A

ValidationError: A detailed error type that includes:

  • Value: The actual value that failed validation
  • Context: The path through nested structures (e.g., "user.address.zipCode")
  • Message: Human-readable error description
  • Cause: Optional underlying error

Context: A stack of ContextEntry values that tracks the validation path through nested data structures, enabling precise error reporting.

Basic Usage

Creating validation results:

// Success case
valid := validation.Success(42)

// Failure case
invalid := validation.Failures[int](validation.Errors{
	&validation.ValidationError{
		Value:    "not a number",
		Message:  "expected integer",
		Context:  nil,
	},
})

Using with context:

failWithMsg := validation.FailureWithMessage[int]("invalid", "must be positive")
result := failWithMsg([]validation.ContextEntry{
	{Key: "age", Type: "int"},
})

Applicative Validation

The validation type supports applicative operations, allowing you to combine multiple validations and accumulate all errors:

type User struct {
	Name  string
	Email string
	Age   int
}

validateName := func(s string) validation.Validation[string] {
	if len(s) > 0 {
		return validation.Success(s)
	}
	return validation.Failures[string](/* error */)
}

// Combine validations - all errors will be collected
result := validation.Ap(validation.Ap(validation.Ap(
	validation.Of(func(name string) func(email string) func(age int) User {
		return func(email string) func(age int) User {
			return func(age int) User {
				return User{name, email, age}
			}
		}
	}),
)(validateName("")))(validateEmail("")))(validateAge(-1))

Error Formatting

ValidationError implements custom formatting for detailed error messages:

err := &ValidationError{
	Value:    "abc",
	Context:  []ContextEntry{{Key: "user"}, {Key: "age"}},
	Message:  "expected integer",
}

fmt.Printf("%v", err)   // at user.age: expected integer
fmt.Printf("%+v", err)  // at user.age: expected integer
                        //   value: "abc"

Monoid Operations

The package provides monoid instances for combining validations:

// Combine validation results
m := validation.ApplicativeMonoid(stringMonoid)
combined := m.Concat(validation.Success("hello"), validation.Success(" world"))
// Result: Success("hello world")

Integration

This package integrates with:

  • either: Validation is built on Either for error handling
  • array: For collecting multiple errors
  • monoid: For combining validation results
  • reader: For context-dependent validation operations

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Applicative

func Applicative[A, B any]() applicative.Applicative[A, B, Validation[A], Validation[B], Validation[func(A) B]]

Applicative creates an Applicative instance for Validation with error accumulation.

This returns a lawful Applicative that accumulates validation errors using the Errors monoid. Unlike the standard Either applicative which fails fast, this validation applicative collects all errors when combining independent validations with Ap.

The returned instance satisfies all applicative laws:

  • Identity: Ap(Of(identity))(v) == v
  • Homomorphism: Ap(Of(f))(Of(x)) == Of(f(x))
  • Interchange: Ap(Of(f))(u) == Ap(Map(f => f(y))(u))(Of(y))
  • Composition: Ap(Ap(Map(compose)(f))(g))(x) == Ap(f)(Ap(g)(x))

Key behaviors:

  • Of: lifts a value into a successful Validation (Right)
  • Map: transforms successful values, preserves failures (standard functor)
  • Ap: when both operands fail, combines all errors using the Errors monoid

This is particularly useful for form validation, configuration validation, and any scenario where you want to collect all validation errors at once rather than stopping at the first failure.

Example - Validating Multiple Fields:

app := Applicative[string, User]()

// Validate individual fields
validateName := func(name string) Validation[string] {
	if len(name) < 3 {
		return Failure("Name must be at least 3 characters")
	}
	return Success(name)
}

validateAge := func(age int) Validation[int] {
	if age < 18 {
		return Failure("Must be 18 or older")
	}
	return Success(age)
}

// Create a curried constructor
makeUser := func(name string) func(int) User {
	return func(age int) User {
		return User{Name: name, Age: age}
	}
}

// Combine validations - all errors are collected
name := validateName("ab")  // Failure: name too short
age := validateAge(16)      // Failure: age too low

result := app.Ap(age)(app.Ap(name)(app.Of(makeUser)))
// result contains both validation errors:
// - "Name must be at least 3 characters"
// - "Must be 18 or older"

Type Parameters:

  • A: The input value type (Right value)
  • B: The output value type after transformation

Returns:

An Applicative instance with Of, Map, and Ap operations that accumulate errors

Types

type Context

type Context = []ContextEntry

Context is a stack of ContextEntry values representing the path through nested structures during validation. Used to provide detailed error messages.

type ContextEntry

type ContextEntry struct {
	Key    string // The key or field name (for objects/maps)
	Type   string // The expected type name
	Actual any    // The actual value being validated
}

ContextEntry represents a single entry in the validation context path. It tracks the location and type information during nested validation.

type Either

type Either[E, A any] = either.Either[E, A]

Either represents a value that can be one of two types: Left (error) or Right (success).

type Errors

type Errors = []*ValidationError

Errors is a collection of validation errors.

type Kleisli

type Kleisli[A, B any] = Reader[A, Validation[B]]

type Monoid

type Monoid[A any] = monoid.Monoid[A]

func ApplicativeMonoid

func ApplicativeMonoid[A any](m Monoid[A]) Monoid[Validation[A]]

ApplicativeMonoid creates a Monoid instance for Validation[A] given a Monoid for A. This allows combining validation results where the success values are also combined using the provided monoid. If any validation fails, all errors are accumulated.

The resulting monoid:

  • Empty: Returns a successful validation with the empty value from the inner monoid
  • Concat: Combines two validations:
  • Both success: Combines values using the inner monoid
  • Any failure: Accumulates all errors

Example:

import "github.com/IBM/fp-go/v2/string"

// Create a monoid for validations of strings
m := ApplicativeMonoid(string.Monoid)

v1 := Success("Hello")
v2 := Success(" World")
combined := m.Concat(v1, v2) // Success("Hello World")

v3 := Failures[string](someErrors)
failed := m.Concat(v1, v3) // Failures with accumulated errors

func ErrorsMonoid

func ErrorsMonoid() Monoid[Errors]

ErrorsMonoid returns a Monoid instance for Errors (array of ValidationError pointers). The monoid concatenates error arrays, with an empty array as the identity element. This is used internally by the applicative operations to accumulate validation errors.

Example:

m := ErrorsMonoid()
combined := m.Concat(errors1, errors2) // Concatenates both error arrays
empty := m.Empty()                      // Returns empty error array

type Operator

type Operator[A, B any] = Kleisli[Validation[A], B]

func Ap

func Ap[B, A any](fa Validation[A]) Operator[func(A) B, B]

Ap applies a validation containing a function to a validation containing a value. This is the applicative apply operation that accumulates errors from both validations. If either validation fails, all errors are collected. If both succeed, the function is applied.

This enables combining multiple validations while collecting all errors:

Example:

// Validate multiple fields and collect all errors
validateUser := Ap(Ap(Of(func(name string) func(age int) User {
	return func(age int) User { return User{name, age} }
}))(validateName))(validateAge)

func Map

func Map[A, B any](f func(A) B) Operator[A, B]

Map transforms the value inside a successful validation using the provided function. If the validation is a failure, the errors are preserved unchanged. This is the functor map operation for Validation.

Example:

doubled := Map(func(x int) int { return x * 2 })(Of(21))
// Result: Success(42)

type Reader

type Reader[R, A any] = reader.Reader[R, A]

Reader represents a computation that depends on an environment R and produces a value A.

func FailureWithError

func FailureWithError[T any](value any, message string) Reader[error, Reader[Context, Validation[T]]]

FailureWithError creates a validation failure with a custom message and underlying cause. Returns a Reader that takes an error, then a Context, and produces a Validation[T] failure. This is useful for wrapping errors from other operations while maintaining validation context.

Example:

fail := FailureWithError[int]("abc", "parse failed")
result := fail(parseErr)([]ContextEntry{{Key: "count", Type: "int"}})

func FailureWithMessage

func FailureWithMessage[T any](value any, message string) Reader[Context, Validation[T]]

FailureWithMessage creates a validation failure with a custom message. Returns a Reader that takes a Context and produces a Validation[T] failure. This is useful for creating context-aware validation errors.

Example:

fail := FailureWithMessage[int]("abc", "expected integer")
result := fail([]ContextEntry{{Key: "age", Type: "int"}})

type Validation

type Validation[A any] = Either[Errors, A]

Validation represents the result of a validation operation. Left contains validation errors, Right contains the successfully validated value.

func Failures

func Failures[T any](err Errors) Validation[T]

Failures creates a validation failure from a collection of errors. Returns a Left Either containing the errors.

func Of

func Of[A any](a A) Validation[A]

Of creates a successful validation result containing the given value. This is the pure/return operation for the Validation monad.

Example:

valid := Of(42) // Validation[int] containing 42

func Success

func Success[T any](value T) Validation[T]

Success creates a successful validation result. Returns a Right Either containing the validated value.

type ValidationError

type ValidationError struct {
	Value    any     // The value that failed validation
	Context  Context // The path to the value in nested structures
	Messsage string  // Human-readable error message
	Cause    error
}

ValidationError represents a single validation failure with context.

func (*ValidationError) Error

func (v *ValidationError) Error() string

Error implements the error interface for ValidationError. Returns a generic error message.

func (*ValidationError) Format

func (v *ValidationError) Format(s fmt.State, verb rune)

Format implements fmt.Formatter for custom formatting of ValidationError. It includes the context path, message, and optionally the cause error. Supports verbs: %s, %v, %+v (with additional details)

func (*ValidationError) String

func (v *ValidationError) String() string

String returns a simple string representation of the validation error. Returns the error message prefixed with "ValidationError: ".

func (*ValidationError) Unwrap

func (v *ValidationError) Unwrap() error

Unwrap returns the underlying cause error if present. This allows ValidationError to work with errors.Is and errors.As.

Jump to

Keyboard shortcuts

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