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

validation

package
v0.5.3 Latest Latest
Warning

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

Go to latest
Published: Nov 3, 2026 License: MIT Imports: 38 Imported by: 0

Documentation

Overview

Package validation provides typed rules and owned validation diagnostics. Generated declarations compose these same rules; transport adapters own decoding, presence discovery and HTTP error mapping.

Index

Constants

View Source
const DefaultConcurrency = 4

Variables

This section is empty.

Functions

func Check added in v0.2.0

func Check[T any](r Rule[T], ctx context.Context, input T, limits Limits) error

Check executes owned callbacks and returns nil only after all applicable checks pass. Input and referenced data must remain unchanged until return. Panics and infrastructure errors remain internal faults. A tree containing application callbacks (Custom, Dynamic, Hook, lookups, Provide, image measurement) runs in one owned goroutine so runtime.Goexit is also contained; other trees run inline without a goroutine, where Goexit in a selector or value method ends the caller like any Go function. Cancellation never abandons a selector or custom rule that still owns work. Valid input allocates no issue storage or JSON Pointer paths.

func CheckProhibitions added in v0.2.0

func CheckProhibitions[T any](r Rule[T], ctx context.Context, input T, limits Limits) error

CheckProhibitions checks only built-in Prohibited/Absent rules on original decoded input before preparation. Conditions retain their original-input semantics. It does not substitute for Check on the prepared value.

func FieldName added in v0.2.0

func FieldName[T, V any](f Field[T, V]) string

FieldName returns the generated transport property name, shared by validation and other typed field consumers. ValidateField rejects an undefined descriptor.

func MessageDefinitions

func MessageDefinitions() []i18n.MessageDefinition

MessageDefinitions registers every built-in rule's translation signature. The returned values are owned snapshots. English fallback text is retained by the rule even when English is not an enabled catalog/request locale.

func Select added in v0.2.0

func Select[T, V any](f Field[T, V], input T) (V, error)

Select reads this exact field without reflection or a second getter map. Like a direct application getter, it executes synchronously; services using custom selectors own callback isolation, cancellation and input lifetime.

func ValidateField added in v0.2.0

func ValidateField[T, V any](f Field[T, V]) error

ValidateField checks the name and selector without executing it.

func ValidateMessages

func ValidateMessages(description Description, catalog *i18n.Catalog) error

ValidateMessages checks a rule description against a catalog at startup. Missing definitions are optional (English fallback); registered signatures and parameter-free label declarations must match. No selectors or checks execute.

func ValidateRule added in v0.2.0

func ValidateRule[T any](r Rule[T]) error

ValidateRule checks the declaration without executing selectors or callbacks. A rule reading a Slot is complete only inside a Provide for that slot.

Types

type AnyLookup

type AnyLookup[T any] interface {
	// Validate checks the lookup's configuration.
	Validate() error
	// AnyExist reports whether any supplied value exists.
	AnyExist(context.Context, []T) (bool, error)
}

AnyLookup reports whether any value of a collection exists, in bounded batches. It backs UniqueAll and UniqueEach with the Lookup ownership contract.

type BatchLookup

type BatchLookup[T any] interface {
	// Validate checks the lookup's configuration.
	Validate() error
	// AllExist reports whether all supplied values exist.
	AllExist(context.Context, []T) (bool, error)
}

BatchLookup checks a collection in bounded batches rather than one remote call per value. Implementations retain the same error/ownership contract as Lookup. Empty input succeeds without I/O; use MinItems to require selection.

type Description

type Description struct {
	Kind          Kind            `json:"kind"`
	Field         string          `json:"field,omitempty"`
	OtherField    string          `json:"other_field,omitempty"`
	Label         string          `json:"label,omitempty"`
	OtherLabel    string          `json:"other_label,omitempty"`
	LabelKey      i18n.MessageKey `json:"label_key,omitempty"`
	OtherLabelKey i18n.MessageKey `json:"other_label_key,omitempty"`
	Spec          *Spec           `json:"spec,omitempty"`
	ServerOnly    bool            `json:"server_only,omitempty"`
	Children      []Description   `json:"children,omitempty"`
}

Description is an owned rule tree. Kind defines composition; Spec describes a leaf. Field carries a declared wire name; Label is its optional static display name. OtherField/OtherLabel describe a comparison target. ServerOnly marks rules whose behavior cannot be promised by a browser validator.

func DescribeRule added in v0.2.0

func DescribeRule[T any](r Rule[T]) (Description, error)

DescribeRule returns an independent snapshot of the same rule tree Check uses. A subtree awaiting its enclosing Provide can still be described.

func (Description) Normalize

func (d Description) Normalize() (Description, error)

Normalize validates and owns serialized inspection metadata. It reuses rule parameter validation and composition budgets; it creates no executable rule and does not claim that a custom/server-only rule runs in a browser.

type DimensionConstraints

type DimensionConstraints struct {
	MinWidth, MaxWidth, MinHeight, MaxHeight int
	Width, Height                            int
	RatioWidth, RatioHeight                  int
}

DimensionConstraints bound an image's pixel size. Zero fields are unbounded; at least one constraint is required. RatioWidth and RatioHeight together require an exact aspect ratio, such as 16 by 9.

func (DimensionConstraints) Validate

func (c DimensionConstraints) Validate() error

Validate checks dimension bounds, paired ratio values, and the presence of at least one constraint.

type Errors

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

Errors reports rejected input. Truncated reports that the issue cap stopped further validation; it does not claim the omitted checks would have failed.

func (*Errors) Error

func (*Errors) Error() string

Error returns the fixed validation failure message.

func (*Errors) Is

func (*Errors) Is(target error) bool

Is reports whether the target is fault.Invalid.

func (*Errors) Issues

func (e *Errors) Issues() []contract.Issue

Issues returns a copy of the validation issues.

func (*Errors) Localize

func (e *Errors) Localize(ctx context.Context, catalog *i18n.Catalog, locale i18n.LocaleID) (*Errors, error)

Localize returns owned labels/messages using a request-independent explicit catalog and locale. Codes, paths, order and truncation are unchanged. Missing translations retain English; conflicting declarations return an error.

func (*Errors) LocalizeLabels

func (e *Errors) LocalizeLabels(ctx context.Context, catalog *i18n.Catalog, locale i18n.LocaleID) (*Errors, error)

LocalizeLabels returns independent diagnostics. Missing registered labels retain their existing static text; declaration/configuration failures return an error. Rule messages remain the rule's approved public text.

func (*Errors) Truncated

func (e *Errors) Truncated() bool

Truncated reports whether validation issues were truncated.

type Field

type Field[T, V any] struct {
	// contains filtered or unexported fields
}

Field retains both the containing request and concrete field value types. Generated declarations own names/selectors; this is their explicit constructor.

func DefineField

func DefineField[T, V any](name string, selector func(T) V) Field[T, V]

DefineField declares a field selector, retaining an error for an invalid name or nil selector.

func WithLabel added in v0.2.0

func WithLabel[T, V any](f Field[T, V], label string) Field[T, V]

WithLabel returns a field with a static public display name. It preserves the wire name, selector and concrete types. Diagnostics keep their JSON Pointer path and carry the label separately; built-in messages use this name. Nested fields select their own labels, while scalar collection items use their containing field's label. Localization produces an owned copy.

func WithLabelKey added in v0.2.0

func WithLabelKey[T, V any](f Field[T, V], key i18n.MessageKey) Field[T, V]

WithLabelKey attaches a parameter-free UI message while preserving the static label as the missing-translation fallback. It never changes the wire path.

type FileValue

type FileValue interface {
	// IsZero reports whether the file value is absent.
	IsZero() bool
	// Size returns the file size in bytes.
	Size() int64
	// ContentType returns the file's content type.
	ContentType() string
	// Extension returns the file's extension.
	Extension() string
}

FileValue supplies captured file metadata. HTTP UploadedFile implements it; domain adapters must supply the same truthful metadata contract. These rules perform no I/O and never consult a client-declared content type. Metadata methods execute within the ordinary owned validation callback boundary.

type ImageMeasurer

type ImageMeasurer[F any] interface {
	// Validate checks the image measurer's configuration.
	Validate() error
	// Measure measures image dimensions, reporting whether the input is a supported image.
	Measure(context.Context, F) (size ImageSize, ok bool, err error)
}

ImageMeasurer reads an image file's dimensions without decoding pixels. ok=false reports a file that is absent, oversized or not a supported image, which rejects the input; an error is an execution failure. The imaging validation adapter supplies this from imaging.Inspect.

type ImageSize

type ImageSize struct{ Width, Height int }

ImageSize is inspected image metadata in displayed orientation.

type Integer

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

Integer restricts exact modulo checks to ordinary or named integer values.

type Kind

type Kind string

Kind identifies validation metadata kinds.

const (
	LeafKind     Kind = "rule"
	AllKind      Kind = "all"
	BailKind     Kind = "bail"
	FieldKind    Kind = "field"
	CompareKind  Kind = "compare"
	OptionalKind Kind = "optional"
	NullableKind Kind = "nullable"
	EachKind     Kind = "each"
	WhenKind     Kind = "when"
	UnlessKind   Kind = "unless"
	PointerKind  Kind = "pointer"
	// EachKeyKind and EachValueKind visit map entries in ascending key order.
	EachKeyKind   Kind = "each_key"
	EachValueKind Kind = "each_value"
)

type LimitError

type LimitError struct{}

LimitError means validation could not complete within its work/value bound. It is distinct from rejected rule input and never establishes a valid result.

func (*LimitError) Error

func (*LimitError) Error() string

Error returns the fixed validation budget exhaustion message.

func (*LimitError) Is

func (*LimitError) Is(target error) bool

Is reports whether the target is fault.Invalid.

type Limits

type Limits struct {
	Checks     int
	Issues     int
	Depth      int
	ValueBytes int
}

Limits bounds one Check. Checks counts rule and field visits; Issues caps retained diagnostics. Depth bounds composition and ValueBytes bounds native text before scanning it. Callbacks own their internal work and allocations.

func DefaultLimits

func DefaultLimits() Limits

DefaultLimits returns default check, issue, depth, and value byte budgets.

func (Limits) Validate

func (l Limits) Validate() error

Validate checks positive validation budgets and the supported depth range.

type Lookup

type Lookup[T any] interface {
	// Validate checks the lookup's configuration.
	Validate() error
	// Exists reports whether the supplied value exists.
	Exists(context.Context, T) (bool, error)
}

Lookup checks whether a concrete value exists in an explicitly scoped source. Validate checks its declaration without I/O. Exists must honor the context and retain ownership of its work until return. The database adapter supplies this contract from ORM declarations; applications can provide other typed sources.

type MapKey

type MapKey interface{ ~string | Integer }

MapKey is a native JSON object key: ordinary or named text or integers. Keys with custom JSON/text codecs are rejected because their wire names are not their native values.

type NowTemporal

type NowTemporal interface {
	time.Time | temporal.DateTime | temporal.LocalDateTime
	// String returns the temporal value's text representation.
	String() string
}

NowTemporal values compare with the current time: instants directly and local date-times with the current wall time in the service's timezone.

type Number

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

Number is the set of integer and floating-point types supported by numeric rules.

type Pair

type Pair[V any] struct{ Left, Right V }

Pair retains both values' concrete type for reusable comparison rules.

type Parameter

type Parameter struct {
	Name  string          `json:"name"`
	Value json.RawMessage `json:"value"`
}

Parameter is declaration metadata, never a received field value. Values are bounded, valid JSON and copied at construction and inspection boundaries.

type PasswordOptions

type PasswordOptions struct {
	MinLength int
	MaxLength int
	Letters   bool
	MixedCase bool
	Numbers   bool
	Symbols   bool
}

PasswordOptions counts Unicode code points. Composition requirements are opt-in; no normalization, trimming, hashing or external breach request occurs.

func DefaultPasswordOptions

func DefaultPasswordOptions() PasswordOptions

DefaultPasswordOptions returns password length bounds of 12 through 128.

func (PasswordOptions) Validate

func (o PasswordOptions) Validate() error

Validate checks that password length bounds are positive and ordered.

type Rejection

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

Rejection is a message chosen at check time. The zero value accepts input. Messages are public text written by the application; never include secrets or unapproved submitted values.

func Reject

func Reject(text string) Rejection

Reject rejects input with literal public text. Empty text uses the rule's declared message (including its translation).

func RejectWith

func RejectWith[A any](translated message.Message[A], args A) Rejection

RejectWith rejects input with a generated typed message whose arguments are computed at check time, such as a remaining quota. It renders in the request locale like built-in messages; the rule's declared message is the English fallback. Arguments are bound only when the rejection is recorded.

type Report

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

Report records Hook issues relative to the hook's input path. It is valid only during the hook call and is not safe for concurrent use.

func (*Report) Add

func (r *Report) Add(path ...string)

Add rejects a location with the hook's declared message. Each path segment is one unescaped JSON object name or array index, relative to the hook's input. No segments address the input itself. Adds past the issue cap are dropped and mark the result truncated.

func (*Report) AddRejection

func (r *Report) AddRejection(rejection Rejection, path ...string)

AddRejection records a location with a check-time message.

type Rule

type Rule[T any] struct {
	// contains filtered or unexported fields
}

Rule retains its concrete input type. It is immutable after construction; Check may run concurrently on independent inputs. The zero value is invalid.

func ASCII

func ASCII[S ~string]() Rule[S]

ASCII creates a rule accepting only ASCII runes.

func Absent

func Absent[T any]() Rule[value.Optional[T]]

Absent requires omission. A supplied zero, empty or null value is still present; use explicit value rules when those representations should be allowed.

func Accepted

func Accepted[B ~bool]() Rule[B]

Accepted and Declined use actual booleans. Text coercion belongs to decoding.

func After

func After[T Temporal](bound T) Rule[T]

After requires a value strictly after its same-type temporal bound.

func AfterField

func AfterField[T any, V Temporal](field, other Field[T, V]) Rule[T]

AfterField requires the first field to be strictly after the second field.

func AfterNow

func AfterNow[T NowTemporal](service temporal.Service) Rule[T]

AfterNow requires a value strictly after the current time. The clock is read at every check, never at construction. Pass the application's temporal service (application Services.Time) so frozen test clocks and the configured timezone apply; a zero Service makes the declaration invalid. Metadata is server-only.

func AfterOrEqual

func AfterOrEqual[T Temporal](bound T) Rule[T]

AfterOrEqual accepts values at or after their same-type temporal bound.

func AfterOrEqualField

func AfterOrEqualField[T any, V Temporal](field, other Field[T, V]) Rule[T]

AfterOrEqualField requires the first field to be at or after the second field.

func AfterOrEqualNow

func AfterOrEqualNow[T NowTemporal](service temporal.Service) Rule[T]

AfterOrEqualNow accepts the current time or later.

func AfterOrEqualToday

func AfterOrEqualToday[T TodayTemporal](service temporal.Service) Rule[T]

AfterOrEqualToday accepts today or a later date.

func AfterToday

func AfterToday[T TodayTemporal](service temporal.Service) Rule[T]

AfterToday requires a calendar date after today in the service's timezone, read at check time. Absent dates and out-of-range instants reject.

func All

func All[T any](rules ...Rule[T]) Rule[T]

All preserves declaration order and accumulates bounded diagnostics.

func Alpha

func Alpha[S ~string]() Rule[S]

Alpha accepts Unicode Alphabetic characters, including alphabetic marks. Empty text passes; use NonBlank for presence. Unicode-table behavior is server-only metadata because browser Unicode versions can differ.

func AlphaDash

func AlphaDash[S ~string]() Rule[S]

AlphaDash creates a rule accepting alphabetic runes, Unicode numbers, hyphens, and underscores.

func AlphaNumeric

func AlphaNumeric[S ~string]() Rule[S]

AlphaNumeric accepts Unicode Alphabetic and Number characters. It does not accept punctuation or normalize combining marks, case or scripts.

func Bail

func Bail[T any](rules ...Rule[T]) Rule[T]

Bail stops this sequence after its first failed rule. Other object fields may still be checked by an enclosing All sequence.

func Before

func Before[T Temporal](bound T) Rule[T]

Before requires a temporal value strictly before its declared bound. Dates and local values compare in calendar order; instants compare in UTC without monotonic readings. No host timezone or current clock is consulted; use the relative BeforeNow/BeforeToday family for bounds read at check time.

func BeforeField

func BeforeField[T any, V Temporal](field, other Field[T, V]) Rule[T]

BeforeField compares two generated fields while preserving their request and temporal value types. Failures use the first field's path; metadata retains both field names. Absent Date/LocalDateTime values reject rather than compare as calendar dates. Optional and nullable states require explicit wrappers.

func BeforeNow

func BeforeNow[T NowTemporal](service temporal.Service) Rule[T]

BeforeNow requires a value strictly before the current time.

func BeforeOrEqual

func BeforeOrEqual[T Temporal](bound T) Rule[T]

BeforeOrEqual also accepts a value equal to the bound, retaining nanoseconds.

func BeforeOrEqualField

func BeforeOrEqualField[T any, V Temporal](field, other Field[T, V]) Rule[T]

BeforeOrEqualField allows equality when comparing two same-type fields.

func BeforeOrEqualNow

func BeforeOrEqualNow[T NowTemporal](service temporal.Service) Rule[T]

BeforeOrEqualNow accepts the current time or earlier.

func BeforeOrEqualToday

func BeforeOrEqualToday[T TodayTemporal](service temporal.Service) Rule[T]

BeforeOrEqualToday accepts today or an earlier date.

func BeforeToday

func BeforeToday[T TodayTemporal](service temporal.Service) Rule[T]

BeforeToday requires a date before today.

func Between

func Between[N Number](minimum, maximum N) Rule[N]

Between combines inclusive numeric bounds, rejecting reversed bounds.

func Compare

func Compare[T, V any](field, other Field[T, V], comparator Rule[Pair[V]]) Rule[T]

Compare binds a reusable comparator to fields with the same request and value types. Failures use the first field's wire path; metadata retains both names. Custom comparators use Custom[Pair[V]] and remain server-only.

func Confirmed

func Confirmed[T any, V Scalar](field, confirmation Field[T, V]) Rule[T]

Confirmed compares explicitly selected fields; it never guesses a suffix.

func Contains

func Contains[S ~string](part S) Rule[S]

Contains creates a rule requiring the supplied substring.

func ContainsItems

func ContainsItems[S ~[]T, T Scalar](members ...T) Rule[S]

ContainsItems requires every declared scalar member at least once. It owns the declaration and scans input once; ExcludesItems prohibits any member.

func Custom

func Custom[T any](spec Spec, check func(context.Context, T) (bool, error)) Rule[T]

Custom defines a typed server rule. Returning false rejects the input with Spec.Message; returning an error means execution failed, not invalid input. Reuse the returned rule value when sharing one definition across fields.

func Date

func Date[S ~string]() Rule[S]

Temporal text rules reuse the framework temporal parsers. Prefer concrete temporal DTO fields when the transport should decode a temporal value directly.

func DateFormat

func DateFormat[S ~string](layout string) Rule[S]

DateFormat accepts text written exactly in a Go reference-time layout, such as "2006-01-02" or "02/01/2006 15:04". The value must parse and format back to the same text, so optional padding and alternative zone spellings reject. The layout must round-trip the reference time. No timezone or clock is consulted; prefer concrete temporal DTO fields when the wire format is RFC 3339.

func DateTime

func DateTime[S ~string]() Rule[S]

DateTime creates a text rule using temporal.ParseDateTime.

func DecimalBetween

func DecimalBetween(minimum, maximum decimal.Decimal) Rule[decimal.Decimal]

DecimalBetween combines inclusive decimal bounds, rejecting reversed bounds.

func DecimalGreaterOrEqual

func DecimalGreaterOrEqual() Rule[Pair[decimal.Decimal]]

DecimalGreaterOrEqual creates a rule requiring the first decimal in a pair to be greater than or equal to the second.

func DecimalGreaterThan

func DecimalGreaterThan() Rule[Pair[decimal.Decimal]]

DecimalGreaterThan and its siblings compare two exact decimal fields through Compare, for example a maximum price against a minimum price. They never convert through floating point; failures use the first field's path.

func DecimalLessOrEqual

func DecimalLessOrEqual() Rule[Pair[decimal.Decimal]]

DecimalLessOrEqual creates a rule requiring the first decimal in a pair to be less than or equal to the second.

func DecimalLessThan

func DecimalLessThan() Rule[Pair[decimal.Decimal]]

DecimalLessThan creates a rule requiring the first decimal in a pair to be less than the second.

func DecimalMax

func DecimalMax(maximum decimal.Decimal) Rule[decimal.Decimal]

DecimalMax creates a rule requiring a decimal no greater than the maximum.

func DecimalMaxPlaces

func DecimalMaxPlaces(maximum int) Rule[decimal.Decimal]

DecimalMaxPlaces limits significant fractional digits. Decimals are canonical, so 1.50 has one place; validate raw text when trailing zeros are significant.

func DecimalMin

func DecimalMin(minimum decimal.Decimal) Rule[decimal.Decimal]

DecimalMin and DecimalMax preserve the framework's exact decimal comparison. Their metadata uses the same string representation as decimal DTO fields.

func DecimalMultipleOf

func DecimalMultipleOf(divisor decimal.Decimal) Rule[decimal.Decimal]

DecimalMultipleOf requires an exact integer quotient, for example a quantity in 0.25 steps. The divisor must be positive; comparison is exact at any scale.

func DecimalPositive

func DecimalPositive() Rule[decimal.Decimal]

DecimalPositive accepts strictly positive decimals at every supported scale. Validation runs on the server, preserving exact decimal comparisons.

func Declined

func Declined[B ~bool]() Rule[B]

Declined creates a rule requiring false.

func Different

func Different[V Scalar]() Rule[Pair[V]]

Different requires unequal scalar values without coercion or normalization.

func Digits

func Digits[S ~string]() Rule[S]

Digits accepts only ASCII digits, preserving leading zeros. Empty text passes; use NonBlank and length rules when the field must contain a fixed-size code.

func DigitsBetween

func DigitsBetween[S ~string](minimum, maximum int) Rule[S]

DigitsBetween validates ASCII numeric text without discarding leading zeros.

func Dimensions

func Dimensions[F any](measurer ImageMeasurer[F], constraints DimensionConstraints) Rule[F]

Dimensions checks an image's pixel size through an explicitly injected measurer. Files that are not supported images reject. Combine it with FileMaxSize so oversized uploads reject before any bytes are read.

func Distinct

func Distinct[S ~[]T, T Scalar]() Rule[S]

Distinct checks scalar slice values with native equality and bounded work. It reports at the collection's path and does not normalize or mutate values.

func DistinctBy

func DistinctBy[S ~[]T, T any, K Scalar](field Field[T, K]) Rule[S]

DistinctBy checks a concrete field of each object without serializing objects. Failures belong to the collection; use Each for per-object value constraints.

func DistinctIgnoringCase

func DistinctIgnoringCase[S ~[]T, T ~string]() Rule[S]

DistinctIgnoringCase checks text elements for duplicates after Unicode case folding, so "Tag" and "tag" collide. Values are not modified. Folding follows the server's Unicode tables, so metadata is server-only.

func DoesntContain

func DoesntContain[S ~string](part S) Rule[S]

DoesntContain creates a rule excluding the supplied substring.

func DoesntEndWith

func DoesntEndWith[S ~string](suffix S) Rule[S]

DoesntEndWith creates a rule excluding the supplied suffix.

func DoesntStartWith

func DoesntStartWith[S ~string](prefix S) Rule[S]

DoesntStartWith creates a rule excluding the supplied prefix.

func Dynamic

func Dynamic[T any](spec Spec, check func(context.Context, T) (Rejection, error)) Rule[T]

Dynamic defines a server rule whose rejection message is decided at check time. Return the zero Rejection to accept and an error when execution fails. Spec supplies the stable code and declared message; built-in IDs are reserved.

func Each

func Each[S ~[]T, T any](rules ...Rule[T]) Rule[S]

Each checks an ordinary or named slice in input order and uses index paths. Empty slices have no elements; collection-size rules are separate.

func EachKey

func EachKey[M ~map[K]V, K MapKey, V any](rules ...Rule[K]) Rule[M]

EachKey checks every key of a map. Entries are visited in ascending key order, so diagnostics are deterministic; each issue uses the entry's path, such as /labels/en. A nil or empty map has no keys. Metadata is server-only.

func EachValue

func EachValue[M ~map[K]V, K MapKey, V any](rules ...Rule[V]) Rule[M]

EachValue checks every value of a map in ascending key order and reports at the entry's path. Use EachKey for key constraints.

func Email

func Email[S ~string]() Rule[S]

Email accepts a single bare mailbox using Go's net/mail parser. Display names, comments, angle wrappers and surrounding whitespace are rejected. It performs no DNS/delivery checks or normalization. Parser semantics remain server-only in metadata rather than claiming browser equivalence.

func Embed

func Embed[Outer, Inner any](rule Rule[Inner], selector func(Outer) Inner) Rule[Outer]

Embed applies an existing rule tree to a concrete value selected from an outer input, retaining the child's wire paths and metadata without a prefix. Use it when the outer transport flattens that value, such as EmbedQuery. Selectors must not mutate or retain input. Their work runs inside the same owned callback boundary and limits as the original rule tree.

func Empty

func Empty[T any]() Rule[T]

Empty accepts blank text and empty collections. It does not treat numeric zero, false or a zero struct as null or omission. Text remains unchanged.

func EndsWith

func EndsWith[S ~string](suffix S) Rule[S]

EndsWith checks an exact, case-sensitive suffix without normalization.

func Enum

func Enum[E enum.Scalar](descriptor enum.Descriptor[E]) Rule[E]

Enum validates a concrete enum from its existing descriptor. Runtime values and actual wire cases share that descriptor; custom enum codecs are owned at construction and do not execute on each input check.

func ExcludesItems

func ExcludesItems[S ~[]T, T Scalar](members ...T) Rule[S]

ExcludesItems creates a rule excluding the supplied member values from a slice.

func Exists

func Exists[T any](lookup Lookup[T]) Rule[T]

Exists requires a matching value in the declared lookup. It is server-only and advisory: later changes can invalidate the observation. Input omission and nullability are handled by the normal Optional/Nullable adapters.

func ExistsAll

func ExistsAll[S ~[]T, T any](lookup BatchLookup[T]) Rule[S]

ExistsAll validates all values against one scoped source. Valid input costs one batched observation (split into the lookup's own statement batches). A rejection is located with bounded additional batch observations and reported at each missing element's index path, such as /tags/3, using the collection's label. The issue does not distinguish a nonexistent value from an inaccessible one. Every item is charged against the shared work budget before any I/O, and each observation costs one further check.

func ExistsEach

func ExistsEach[S ~[]E, E, V any](field Field[E, V], lookup BatchLookup[V]) Rule[S]

ExistsEach selects one field from every object of a collection and checks the selected values with batched observations instead of one call per element. Missing values are reported at the element's field path, for example /items/3/product_id, using that field's label.

func FileContentTypes

func FileContentTypes[F FileValue](allowed ...string) Rule[F]

FileContentTypes compares detected MIME media types. Declarations may use an exact type, a major-type wildcard such as image/*, or */*. Parameters such as charset do not participate in matching. The HTTP detector is a bounded sniff, not full image/document validation; imaging validation belongs to that adapter. Rules remain server-only because browser file.type is client metadata.

func FileExtensions

func FileExtensions[F FileValue](allowed ...string) Rule[F]

FileExtensions compares the normalized final filename extension without a leading dot. An allowed extension never proves the file's actual content; combine it with a detected content-type rule when that behavior is required.

func FileMaxSize

func FileMaxSize[F FileValue](maximum int64) Rule[F]

FileMaxSize compares bytes without converting through floating point.

func FileMinSize

func FileMinSize[F FileValue](minimum int64) Rule[F]

FileMinSize compares exact byte counts, including an inclusive zero bound.

func FilePresent

func FilePresent[F FileValue]() Rule[F]

FilePresent rejects an absent handle. A captured zero-byte file is present; use FileMinSize(1) when nonempty content is required. Optional and Required adapters retain the separate question of whether the form part was supplied.

func GreaterOrEqual

func GreaterOrEqual[N Number]() Rule[Pair[N]]

GreaterOrEqual creates a rule requiring the first number in a pair to be greater than or equal to the second.

func GreaterThan

func GreaterThan[N Number]() Rule[Pair[N]]

GreaterThan creates a rule requiring the first number in a pair to be greater than the second.

func HexColor

func HexColor[S ~string]() Rule[S]

HexColor accepts CSS hexadecimal colors (#RGB, #RGBA, #RRGGBB, #RRGGBBAA).

func Hook

func Hook[T any](spec Spec, hook func(context.Context, T, *Report) error) Rule[T]

Hook runs an application callback that may add issues at arbitrary paths below its input, for checks spanning several fields or collection elements. Place it after field rules in Bail when it needs them to pass first. Returning an error means execution failed, not invalid input. Spec supplies the issue code and declared message; built-in IDs are reserved.

func IP

func IP[S ~string]() Rule[S]

IP accepts a literal IPv4 or IPv6 address without a zone or CIDR suffix.

func IPv4

func IPv4[S ~string]() Rule[S]

IPv4 creates an IPv4 address text rule.

func IPv6

func IPv6[S ~string]() Rule[S]

IPv6 creates an IPv6 address text rule.

func Items

func Items[S ~[]T, T any](count int) Rule[S]

Items requires exactly count elements, including on named slice types.

func ItemsBetween

func ItemsBetween[S ~[]T, T any](minimum, maximum int) Rule[S]

ItemsBetween combines inclusive minimum and maximum item rules, rejecting reversed bounds.

func JSON

func JSON[S ~string]() Rule[S]

JSON validates bounded JSON text through the same strict parser as DTOs. Duplicate keys are rejected; the original string remains unchanged.

func Length

func Length[S ~string](count int) Rule[S]

Length requires exactly count Unicode code points.

func LengthBetween

func LengthBetween[S ~string](minimum, maximum int) Rule[S]

LengthBetween combines inclusive text length bounds, rejecting reversed bounds.

func LessOrEqual

func LessOrEqual[N Number]() Rule[Pair[N]]

LessOrEqual creates a rule requiring the first number in a pair to be less than or equal to the second.

func LessThan

func LessThan[N Number]() Rule[Pair[N]]

LessThan creates a rule requiring the first number in a pair to be less than the second.

func LocalDateTime

func LocalDateTime[S ~string]() Rule[S]

LocalDateTime creates a text rule using temporal.ParseLocalDateTime.

func Locales

func Locales[M ~map[i18n.LocaleID]V, V ~string](catalog i18n.LocaleCatalog, require i18n.LocaleRequirement) Rule[M]

Locales checks a locale-keyed map, such as translated text, against one locale catalog snapshot per check. Every key must be a supported locale (foundry.supported_locale at the entry path, such as /title/fr), and every locale require selects must be present with nonempty content (foundry.required at its entry path, such as /title/ms). The catalog is runtime configuration, so the rule is server-only metadata.

func Lowercase

func Lowercase[S ~string]() Rule[S]

Lowercase and Uppercase check case without changing the received text. Uncased characters pass; nonempty/letter requirements are separate rules.

func MACAddress

func MACAddress[S ~string]() Rule[S]

MACAddress accepts a six-byte address in formats supported by net.ParseMAC.

func Matches

func Matches[S ~string](pattern string) Rule[S]

Matches uses Go's regexp semantics. It is server-only metadata because a JavaScript regular expression does not promise identical syntax or behavior.

func Max

func Max[N Number](maximum N) Rule[N]

Max creates an inclusive maximum rule, rejecting nonfinite bounds and inputs.

func MaxBytes

func MaxBytes[S ~string](maximum int) Rule[S]

MaxBytes limits the UTF-8 encoded size of text, for storage bounds measured in bytes. MaxLength counts characters instead. It is server-only metadata.

func MaxDigits

func MaxDigits[S ~string](maximum int) Rule[S]

MaxDigits combines digit-only validation with a maximum length.

func MaxItems

func MaxItems[S ~[]T, T any](maximum int) Rule[S]

MaxItems creates a rule limiting slice length, rejecting a negative maximum.

func MaxLength

func MaxLength[S ~string](maximum int) Rule[S]

MaxLength creates a rule limiting Unicode rune count, rejecting a negative maximum.

func Min

func Min[N Number](minimum N) Rule[N]

Min and Max compare in N itself; integers never pass through a floating-point comparison. Floating-point bounds and input values must be finite.

func MinDigits

func MinDigits[S ~string](minimum int) Rule[S]

MinDigits combines digit-only validation with a minimum length.

func MinItems

func MinItems[S ~[]T, T any](minimum int) Rule[S]

MinItems and MaxItems validate ordinary or named slices. Nil and empty slices both have zero items; omitted/null transport states use their own wrappers.

func MinLength

func MinLength[S ~string](minimum int) Rule[S]

MinLength measures Unicode code points, not bytes or grapheme clusters.

func MultipleOf

func MultipleOf[N Integer](divisor N) Rule[N]

MultipleOf uses exact integer remainder. The divisor must be positive.

func NonBlank

func NonBlank[S ~string]() Rule[S]

NonBlank rejects empty or whitespace-only text. It leaves the value intact; normalization belongs to explicit domain behavior or model mutators.

func NonEmpty

func NonEmpty[T any]() Rule[T]

NonEmpty rejects blank text and empty collections without inferring wire presence. Zero numbers, false and ordinary structs pass. Domain validity is separate. Use Optional/Nullable/Pointer to unwrap those representations.

func NotMatches

func NotMatches[S ~string](pattern string) Rule[S]

NotMatches rejects text matching a Go regular expression.

func NotNil

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

NotNil rejects nil pointers without dereferencing them.

func NotNull

func NotNull[T any]() Rule[value.Nullable[T]]

NotNull rejects explicit null. Presence is a separate Optional contract.

func NotOneOf

func NotOneOf[K Scalar](values ...K) Rule[K]

NotOneOf rejects any declared scalar value. Non-finite numbers and invalid UTF-8 are rejected even when they are absent from the exclusion list.

func Nullable

func Nullable[T any](rules ...Rule[T]) Rule[value.Nullable[T]]

Nullable skips explicit null and validates a present value. Combine it with Optional for a patch that distinguishes omitted, null and replacement values.

func OneOf

func OneOf[K Scalar](values ...K) Rule[K]

OneOf accepts one of the declared scalar values without coercion. Input and declaration values retain their concrete type; empty/duplicate lists fail.

func Optional

func Optional[T any](rules ...Rule[T]) Rule[value.Optional[T]]

Optional skips an omitted value and validates present values, including zero. It does not infer wire presence from an ordinary Go field's zero value.

func Parallel

func Parallel[T any](rules ...Rule[T]) Rule[T]

Parallel checks independent branches with DefaultConcurrency workers. Each branch retains normal All/Bail order. Use a concurrency-safe pool or client; a transaction or other serial dependency belongs in a sequential branch.

func ParallelLimit

func ParallelLimit[T any](concurrency int, rules ...Rule[T]) Rule[T]

ParallelLimit runs bounded waves, merges issues in declaration order, and shares one work budget. Nested parallel groups execute sequentially inside their branch, so nesting cannot multiply concurrency or deadlock workers. All admitted callbacks finish before return, including after cancellation, panic or Goexit. Inputs/selectors/dependencies must support concurrent reads. Metadata is logical All, server-only; scheduling is not a wire contract.

func Password

func Password[S ~string](options PasswordOptions) Rule[S]

Password creates a password rule using the supplied options.

func PasswordValue

func PasswordValue[P interface{ Secret() secret.String }](options PasswordOptions) Rule[P]

PasswordValue accepts redacted password input such as auth/password.Plaintext. The secret is inspected only during Check and never enters public metadata.

func Pointer

func Pointer[T any](rules ...Rule[T]) Rule[*T]

Pointer skips nil and validates a non-nil pointed-to value. It does not infer wire presence: an ordinary pointer can represent both omission and null.

func Positive

func Positive[N Number]() Rule[N]

Positive accepts only strictly positive, finite numbers. Zero, including negative floating-point zero, is rejected. This rule is server-only until the TypeScript runtime supports foundry.positive.

func Present

func Present[T any]() Rule[value.Optional[T]]

Present requires an Optional to have been supplied; its inner zero or null remains distinct and can be checked by additional value rules.

func Prohibited

func Prohibited[T any]() Rule[value.Optional[T]]

Prohibited accepts omission or empty content. Unlike Absent, supplied blank text and empty collections pass. Supplied numeric zero and false reject. Use ProhibitedNullable when explicit null is a representable input state.

func ProhibitedNullable

func ProhibitedNullable[T any]() Rule[value.Optional[value.Nullable[T]]]

ProhibitedNullable also accepts explicit null, while preserving the distinction from omission and a nonempty T. It does not mutate or unset supplied values.

func Provide

func Provide[T, P any](slot Slot[P], derive func(context.Context, T) (P, error), rules ...Rule[T]) Rule[T]

Provide derives the slot's value from the check context and the input at this level, then runs rules with that value available to their contexts. For HTTP, attach it with WithValidation so derive can read path parameters while the rules select body fields. derive is an application callback: its error is an execution failure, never a rejection or an absent value. The value is visible only to this subtree and only for the current check.

func Required

func Required[T any](rules ...Rule[T]) Rule[value.Optional[T]]

Required requires a supplied, nonempty Optional value. Supplied numeric zero and false pass. Additional same-type rules run only after that requirement succeeds and bail on the first rejection. For nullable input use RequiredNullable; ordinary fields use NonEmpty without inferring presence.

func RequiredNullable

func RequiredNullable[T any](rules ...Rule[T]) Rule[value.Optional[value.Nullable[T]]]

RequiredNullable distinguishes omission, explicit null and supplied T. Null and empty content reject; zero numbers and false remain valid supplied values. Additional T rules run only on the nonempty, non-null value and bail on failure.

func Requires

func Requires[T, P any](slot Slot[P], rule Rule[T]) Rule[T]

Requires records that rule reads slot. Validate then rejects any tree in which no enclosing Provide supplies it, so a missing provider fails registration instead of every check. Adapters that accept a Slot apply this themselves.

func Rules added in v0.2.0

func Rules[T, V any](f Field[T, V], rules ...Rule[V]) Rule[T]

Rules binds value rules to this field without dynamic field lookups. The selector runs once for this binding and must not mutate the input.

func Same

func Same[V Scalar]() Rule[Pair[V]]

Same requires equal scalar values without coercion or normalization.

func StartsWith

func StartsWith[S ~string](prefix S) Rule[S]

StartsWith checks an exact, case-sensitive prefix without normalization. An empty prefix matches every string; use NonBlank to require nonempty text.

func Time

func Time[S ~string]() Rule[S]

Time creates a text rule using temporal.ParseTime.

func Timezone

func Timezone[S ~string]() Rule[S]

Timezone accepts UTC, an installed IANA zone or a fixed +/-HH:MM offset. It rejects implicit machine-local zones and retains server-only metadata.

func ULID

func ULID[S ~string]() Rule[S]

ULID checks the 26-character Crockford encoding, including its 128-bit bound. Lowercase input is accepted. It does not require a particular timestamp.

func URL

func URL[S ~string]() Rule[S]

URL accepts an absolute HTTP or HTTPS URL with a hostname. It checks syntax, not reachability or whether a destination is authorized for outbound fetching.

func UUID

func UUID[S ~string]() Rule[S]

UUID reuses the framework's canonical hyphenated UUID parser. It checks representation, including the nil UUID; model identity constraints are separate.

func Unique

func Unique[T any](lookup Lookup[T]) Rule[T]

Unique requires no matching value in the declared lookup. It does not reserve the value or replace a database unique constraint. A lookup failure is an internal execution failure, never evidence that the value is available.

func UniqueAll

func UniqueAll[S ~[]T, T any](lookup AnyLookup[T]) Rule[S]

UniqueAll requires that no value of a collection exists in the scoped source, reporting each conflicting element at its index path. It does not detect duplicates inside the request itself; combine it with Distinct.

func UniqueEach

func UniqueEach[S ~[]E, E, V any](field Field[E, V], lookup AnyLookup[V]) Rule[S]

UniqueEach selects one field from every object and requires that none of the selected values exists in the scoped source, reporting conflicts at the element's field path. It is advisory and does not reserve values; combine it with DistinctBy for duplicates inside the request.

func Unless

func Unless[T any](condition Rule[T], rules ...Rule[T]) Rule[T]

Unless runs rules only when the condition rejects its input. A failed or incomplete condition never counts as an ordinary false condition.

func Uppercase

func Uppercase[S ~string]() Rule[S]

Uppercase creates a rule requiring text to equal its uppercase form.

func When

func When[T any](condition Rule[T], rules ...Rule[T]) Rule[T]

When runs rules only when the condition passes. Conditions are ordinary typed rules and may reference generated fields. Their rejection diagnostics remain private; infrastructure failures and cancellation still fail the whole check.

func WithMessage added in v0.2.0

func WithMessage[T any](r Rule[T], message string) Rule[T]

WithMessage replaces only the public message of one leaf. Composite trees retain their individual messages; overriding a composite is rejected.

func WithTranslation

func WithTranslation[T, A any](rule Rule[T], translated message.Message[A], args A) Rule[T]

WithTranslation attaches a generated, typed message to a leaf rule. Arguments are public declaration data, evaluated and snapshotted once; never pass received secrets. Optional text arguments attribute/other receive the bound field labels. The rule's current message is the English fallback. WithMessage restores a literal override; it is not parsed as a template.

type RuleID

type RuleID string

RuleID identifies a rule independently of its public message. Built-in IDs use the reserved foundry namespace; application rules use semantic IDs.

const (
	EmailRuleID RuleID = "foundry.email"
	URLRuleID   RuleID = "foundry.url"
)

Rule IDs of built-in formats that metadata owners, such as client presentation checks, recognize in rule descriptions.

type Scalar

type Scalar interface {
	Number | ~string | ~bool
}

Scalar includes ordinary and named numeric, text and boolean values.

type Slot

type Slot[P any] struct {
	// contains filtered or unexported fields
}

Slot declares a typed value that an enclosing Provide derives once per check from the request context and the input it validates, such as the key of the row being updated or the tenant of the authenticated actor. Rules and lookups below that Provide read it with Value, so a rule tree is declared once and parameterized at check time instead of being rebuilt for every request. Declare slots once, beside the rules that use them. The zero Slot is invalid.

func NewSlot

func NewSlot[P any]() Slot[P]

NewSlot creates a typed validation slot with a distinct identity.

func (Slot[P]) Value

func (s Slot[P]) Value(ctx context.Context) (P, error)

Value returns the value provided for the current check. Outside a Provide for this slot it returns an error, never a zero value, so a lookup scoped by the slot cannot silently widen or skip its predicate.

type Spec

type Spec struct {
	ID          RuleID              `json:"id"`
	Message     string              `json:"message"`
	Parameters  []Parameter         `json:"parameters,omitempty"`
	Translation *i18n.MessageRecipe `json:"translation,omitempty"`
}

Spec is a custom rule's public declaration. Message contains approved static public text; an execution error's text is never used as a validation message.

type Temporal

type Temporal interface {
	time.Time | temporal.Date | temporal.Time | temporal.DateTime | temporal.LocalDateTime
	// String returns the temporal value's text representation.
	String() string
}

Temporal retains the distinction between instants, dates and wall times. A bound or related field must have the same concrete type as the input.

type TodayTemporal

type TodayTemporal interface {
	time.Time | temporal.DateTime | temporal.Date | temporal.LocalDateTime
	// String returns the temporal value's text representation.
	String() string
}

TodayTemporal values compare by calendar date with today in the service's timezone. Instants are first converted to their date in that timezone.

Directories

Path Synopsis
Package database supplies advisory typed model validation.
Package database supplies advisory typed model validation.
Package imaging validates uploaded image files with the framework's bounded container inspection.
Package imaging validates uploaded image files with the framework's bounded container inspection.

Jump to

Keyboard shortcuts

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