Help us shape the future of Go! Take the 2026 Go Developer Survey

validate

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Sep 1, 2026 License: MIT Imports: 2 Imported by: 0

README

validate

CI Go Reference

A small error accumulator, so a Validate method reports every problem in one pass instead of failing on the first.

  • One report instead of three round trips - fixing one problem should not be how you discover the next.
  • The zero value is ready to use - nothing to construct.
  • No dependencies outside the standard library.
go get github.com/uchaloop/validate

Use

func (c Config) Validate() error {
	var errs validate.Errors

	errs.Require(c.Timeout > 0, "timeout must be positive, got %s", c.Timeout)
	errs.Require(len(c.Host) != 0, "host is required")

	return errs.Err()
}
timeout must be positive, got -1s
host is required

Add records an error when it is non-nil, Addf formats a new one, and Require records one when a condition does not hold. Err joins what was recorded, or returns nil when nothing was, and errors.Is and errors.As still reach each recorded error.

Documentation

What each method records and the reasons behind the design are in the package documentation: pkg.go.dev/github.com/uchaloop/validate.

License

MIT

Documentation

Overview

Package validate provides a small error accumulator, so a Validate method reports every problem in one pass instead of failing on the first. It depends on nothing outside the standard library.

Why accumulate

A method that returns on its first problem reports one problem. Whoever has to fix them finds the next one only by fixing this one and running again, which turns three mistakes into three round trips. Accumulating turns them into one report:

func (c Config) Validate() error {
	var errs validate.Errors

	errs.Require(c.Timeout > 0, "timeout must be positive, got %s", c.Timeout)
	errs.Require(len(c.Host) != 0, "host is required")

	return errs.Err()
}

timeout must be positive, got -1s
host is required

That matters most where the round trip is expensive - a value fixed somewhere else and applied again, rather than a line edited and rerun.

Recording

The zero value is ready to use, so an Errors is declared and written to; there is nothing to construct.

Add records an error when it is non-nil, which is what makes the common "call something, keep what it said" line a single statement. Addf formats a new one, and %w wraps the cause the way fmt.Errorf does. Require records a formatted error when a condition does not hold - it states what has to be true, rather than what must not be, which is how the check reads in the report it produces.

Err joins what was recorded, or returns nil when nothing was, so a Validate ends in one line whatever it found. The join keeps errors.Is and errors.As reaching each recorded error, and renders them one per line.

Example
package main

import (
	"fmt"
	"time"

	"github.com/uchaloop/validate"
)

type Config struct {
	Host    string
	Timeout time.Duration
}

// Validate reports every problem in one pass. A config is fixed in a deployment
// and rolled out, so one report is one round trip.
func (c Config) Validate() error {
	var errs validate.Errors

	errs.Require(c.Timeout > 0, "timeout must be positive, got %s", c.Timeout)
	errs.Require(len(c.Host) != 0, "host is required")

	return errs.Err()
}

func main() {
	err := Config{Timeout: -time.Second}.Validate()

	fmt.Println(err)
}
Output:
timeout must be positive, got -1s
host is required

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Errors

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

Errors collects validation errors. The zero value is ready to use.

func (*Errors) Add

func (e *Errors) Add(err error)

Add records err when it is non-nil.

func (*Errors) Addf

func (e *Errors) Addf(format string, args ...any)

Addf records a new formatted error.

func (*Errors) Err

func (e *Errors) Err() error

Err returns all accumulated errors joined into one, or nil when there are none. The result works with errors.Is/As over each recorded error.

Example (Valid)
package main

import (
	"fmt"
	"time"

	"github.com/uchaloop/validate"
)

type Config struct {
	Host    string
	Timeout time.Duration
}

// Validate reports every problem in one pass. A config is fixed in a deployment
// and rolled out, so one report is one round trip.
func (c Config) Validate() error {
	var errs validate.Errors

	errs.Require(c.Timeout > 0, "timeout must be positive, got %s", c.Timeout)
	errs.Require(len(c.Host) != 0, "host is required")

	return errs.Err()
}

func main() {
	err := Config{Host: "store:9000", Timeout: 30 * time.Second}.Validate()

	fmt.Println(err)
}
Output:
<nil>

func (*Errors) Require

func (e *Errors) Require(cond bool, format string, args ...any)

Require records a formatted error when cond is false. It is the convenient path for "field X is required" style checks.

Jump to

Keyboard shortcuts

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