Documentation
¶
Overview ¶
Package validate provides type-safe validation with translated messages and errors keyed by JSON Pointer. It depends only on the standard library.
Construction and execution ¶
Construct schemas once, then share them between concurrent Validate, Parse and JSONSchema calls. Published schemas expose execution and inspection only. All settings belong to temporary typed drafts and return that same draft.
Example:
type Signup struct {
Email, Password, Confirm, Plan string
}
schema := validate.Struct(func(object *validate.StructBuilder[Signup]) {
object.Field("Email", func(email *validate.StringBuilder[string]) {
email.Trim().Required().Email()
})
object.Field("Password", func(password *validate.StringBuilder[string]) {
password.Required().Min(12)
})
object.Field("Confirm", func(confirm *validate.StringBuilder[string]) {
confirm.EqField("Password")
})
object.Field("Plan", func(plan *validate.StringBuilder[string]) {
plan.OneOf("free", "pro").Default("free")
})
})
input := Signup{
Email: "ada@example.com",
Password: "correct horse",
Confirm: "correct horse",
}
value, err := schema.Parse(context.Background(), input)
if err != nil {
panic(err)
}
fmt.Println(value.Plan)
Constructor and child callbacks run once, synchronously, in argument order on one fresh draft. Nil supplied callbacks and application panics propagate; expanded nil or empty callback slices omit edits. Publication detaches owned containers, so retained drafts cannot change a schema. Unregistered struct fields and unconfigured collection children receive no validation. Composite children use concrete typed callbacks: Field for structs, Values for slices, Keys and Values for maps, and Value for pointer pointees. Ptr also adapts an explicit published pointee schema. Rule-builder Use imports the same concrete schema role, as a value or nonnil pointer, with the exact value type. NamedBuilder instead explicitly adapts one compatible container schema. InferSchema may also contribute type-only documentation, but never supplies missing child validators. FromJSONSchema returns a separate decoded-JSON validator, not a Schema[T] accepted by Use. Other roles are rejected rather than losing their child validation. Schema-level rules accumulate; overlapping child imports fail construction. Disjoint map key/value imports are allowed. Local child setters replace earlier local definitions but cannot replace a child imported by Use. Ptr's bare, unconfigured scalar adapter may yield to a shared pointee; configured or composite adapters cannot be overwritten.
String, Int, Uint, Float and Bool support built-in and named scalar types. Their type arguments are inferred from typed callbacks. Without callbacks, write String[string]() or Int[int](). Time, Any and File have fixed types; Text supports types with text marshaling and unmarshaling methods, including Duration. Struct and child definitions require exact Go types, not conversion. Duration encodes Go duration text; plain time.Duration is not JSON-compatible. Duration and StringBuilder.Duration export the custom "go-duration" format. FromJSONSchema enforces that format with time.ParseDuration; the standard "duration" format instead uses the incompatible RFC 3339 Appendix A grammar. Named adapts an existing slice or map schema to an identical named container, including through NamedBuilder child callbacks. It preserves source rules and input ownership without introducing a separate family of collection builders. Infer recognizes JSONTypeProvider's explicit native container declaration; custom marshalers without that opt-in remain unconstrained metadata.
StringBuilder.URL requires an absolute URL with a host and an allowed scheme, compared case-insensitively. The default schemes are http and https. An explicit list replaces them and is copied when URL is called, not at publication. Empty entries do not permit relative or scheme-relative references; an empty list selects the defaults. Like other ordinary rules, URL skips absent strings.
Presence, defaults and normalization ¶
Scalar zero values, nil pointers and nil collections are absent. An allocated empty collection and an allocated pointer to zero are present. A time.Time is absent at the zero instant, regardless of its location. Optional absent values skip value constraints. Slice elements, map keys/values and nonnil pointer pointees are forced present, so their zero values are checked. For example, an optional integer with Min(1) accepts zero; use Required or a pointer when zero must be range-checked. Prefer Accepted or Declined for boolean intent. Struct always checks registered fields; Ptr makes it optional.
Default fills an absent value. Required and Default cannot be combined. Struct checks each registered default against its schema during construction. Unconditional normalizers and defaults in reachable nested validated fields run before conditions, regardless of Go field order. Nil intermediate pointers are not allocated, except by explicit pointer defaults. A promoted field behind a nil embedded pointer is checked as zero without normalization.
Normalizers run before presence, defaults and rules, in their own call order. String Trim, ToLower, ToUpper, TrimPrefix, TrimSuffix and Truncate; numeric Abs, Clamp and Round; Time UTC; slice Sort, Filter, Reject, RejectZero and Dedupe; and custom Normalize functions change values. Element and pointee normalization precedes collection normalization. Diagnostics use normalized indexes. Map keys cannot be normalized because that would change identity. Parse copies struct values, pointees and collection storage before changes; it never mutates caller-owned input. Functions, captures and arbitrary default objects retain application ownership. Custom callbacks must not mutate inputs or data reachable from them. Validate and Parse agree on pass or fail.
Conditions and field paths ¶
ConditionBuilder records pure read-only observations of the nearest enclosing struct. Eq, NotEq, In, NotIn, Present, Absent and generic If drive RequiredIf, RequiredUnless, ProhibitedIf, ProhibitedUnless and ExcludeIf. When takes one condition callback followed by typed rule callbacks. Multiple observations are ANDed; And, Or and Not create nonempty groups. If requires the exact enclosing struct type. Conditions never change values or emit diagnostics.
Paths use dot-separated Go field names through structs and pointer-to-struct fields, including promoted fields. JSON names, collection indexes, map keys and parent selectors are not supported. Binding checks path and value types at construction. Nil intermediate pointers make the observation absent without allocation. Eq, NotEq, In and NotIn return false for unresolved paths; explicit Not complements that false result. Direct scalar zeros compare normally. Present distinguishes nil from allocated empty collections and zero pointees.
EqField, NeField, numeric field comparisons and time field comparisons use the same resolver and exact type checks. An unreachable comparison target fails rather than silently comparing a fabricated zero. RequiredWith variants use the same presence semantics. ExcludeIf clears its value and later rules skip it. When and exclusions remain order-sensitive after unconditional preparation.
Collections ¶
Slice and map drafts offer Contains, Every, UniqueBy and CountWhere. Predicates receive exact index/value or key/value pairs and must be pure. Every reports every failing entry. UniqueBy reports each duplicate with the first conflicting key or index; map traversal and diagnostics use sorted diagnostic-name order. Encodable keys use their JSON-v2 object names, including custom JSON or text marshaling. Other Go keys retain fmt.Sprint names. Colliding names share a pointer without losing violations; their relative order is unspecified. Map Has, HasAny and HasAll test key existence even when stored values are zero. Empty key lists make HasAny false and HasAll true. Nil optional collections skip assertions; present empty collections fail Contains and pass Every and uniqueness. CountWhere checks a real zero count with forced presence. Its callbacks accept pure integer constraints only: no defaults, normalization, presence, conditions, field references, exclusions or Check functions. ConditionBuilder offers the same pure collection observations on typed paths.
Failures and construction errors ¶
Rules run in declaration order; Bail stops a value after its first failure. Check returns Fail for a validation failure, At for an object field failure, or an operational error that propagates unchanged. Errors maps JSON Pointers to Violation records with stable codes, parameters and localized messages. Errors.All iterates deterministically. Pointers use encoding/json/v2 field names and RFC 6901 escaping. Registration and path selectors use Go names. Cancellation stops between callbacks and child values and discards partial results. An earlier operational error retains precedence over cancellation.
Fail and At capture acyclic slices, arrays and string-keyed maps recursively, including containers reached through interfaces. Named container and scalar types and nil-versus-empty distinctions are preserved. Engine-created violations detach supported containers before rendering and publication, including built-in and imported enum/const parameters. Errors.Localize copies them again, even for unknown codes whose messages stay unchanged. Struct fields, pointers and non-string-keyed maps are not traversed; native objects, functions and captures retain application ownership. This is not a general object deep copy or JSON conversion. Errors.Add retains supplied parameters, and Errors.All yields borrowed violation slices and parameters. Do not mutate shared diagnostics or opaque objects concurrently with readers. Parameters need to be JSON-serializable only if the diagnostics will be encoded.
Construction mistakes are not user-input violations. Struct reports recorded rule and registration problems together after its declaration callbacks, sorted by Go name with registration order for ties. Recorded problems survive later settings, Use and publication. Examples include negative string lengths, negative MultipleOf factors, non-finite floating constraint bounds and factors, invalid shared schemas, wrong field types and invalid field paths. Some setters still reject immediately: MultipleOf(0), for example, panics before later callbacks run. Supplied nil callbacks and application panics also propagate.
Standalone Parse and Validate on invalid explicit definitions panic with an error wrapping ErrInvalidSchema during compilation. JSONSchema instead returns nil bytes and an error wrapping that sentinel. Omitted collection child rules are valid; a zero unconstructed composite schema is not. In particular, a zero StructSchema is invalid even when adapted with Ptr. Use Struct[T]() for a valid definition with no registered fields. InferSchema returns inference errors from its execution and export methods rather than panicking.
JSON Schema and localization ¶
JSONSchema renders a deterministic 2020-12 subset. Describe adds an annotation, never an error override. Runtime functions, normalization, conditions and cross-field rules are omitted instead of being misrepresented. Their definitions are still checked: export does not run Check, Normalize, condition or collection predicates, replay construction callbacks, or verify defaults against rules. Default annotations retain the supplied value without normalization. Repeated annotations use the last value while runtime rules accumulate; Go absence semantics and numeric representation also prevent a general lossless round trip. Encoding failures return nil bytes and preserve the encoder's error cause.
Infer derives type-only documentation without adding runtime constraints. FromJSONSchema validates decoded JSON using the supported subset and rejects unknown keywords. A pattern keyword must be a string: null, booleans, numbers, arrays and objects return an error wrapping ErrInvalidSchema with the keyword's JSON Pointer. An empty string is a valid pattern. Patterns use Go regular expressions, not necessarily the ECMA 262 syntax used by another JSON Schema consumer. The decoded-JSON validator's runtime copying and traversal respect context cancellation. Oversized arrays report size errors without traversing contents. uniqueItems uses exact structural keys; input must be finite and acyclic. Bound untrusted input bytes, nesting and cardinality. JSON presence semantics differ from Go zero absence.
Messages use Catalog and locale values from NewCatalogContext and NewLocaleContext. Lookup tries the locale, its base language, the catalog default and its base language, built-in English, then the code. Templates use {param} placeholders. English returns a mutable copy; Errors.Localize rerenders existing violations. NewClockContext replaces the clock behind Future and Past. The package keeps no global mutable configuration.
Index ¶
- Variables
- func At(field, code string, params map[string]any) error
- func Fail(code string, params map[string]any) error
- func LocaleFromContext(ctx context.Context) (string, bool)
- func NewCatalogContext(ctx context.Context, catalog Catalog) context.Context
- func NewClockContext(ctx context.Context, now func() time.Time) context.Context
- func NewLocaleContext(ctx context.Context, locale string) context.Context
- type AnyBuilder
- func (draft *AnyBuilder) Bail() *AnyBuilder
- func (draft *AnyBuilder) Check(fn func(context.Context, any) error) *AnyBuilder
- func (draft *AnyBuilder) Default(value any) *AnyBuilder
- func (draft *AnyBuilder) Describe(text string) *AnyBuilder
- func (draft *AnyBuilder) EqField(field string) *AnyBuilder
- func (draft *AnyBuilder) ExcludeIf(configure ...ConditionBuilderFunc) *AnyBuilder
- func (draft *AnyBuilder) NeField(field string) *AnyBuilder
- func (draft *AnyBuilder) Normalize(fn func(any) any) *AnyBuilder
- func (draft *AnyBuilder) ProhibitedIf(configure ...ConditionBuilderFunc) *AnyBuilder
- func (draft *AnyBuilder) ProhibitedUnless(configure ...ConditionBuilderFunc) *AnyBuilder
- func (draft *AnyBuilder) Required() *AnyBuilder
- func (draft *AnyBuilder) RequiredIf(configure ...ConditionBuilderFunc) *AnyBuilder
- func (draft *AnyBuilder) RequiredUnless(configure ...ConditionBuilderFunc) *AnyBuilder
- func (draft *AnyBuilder) RequiredWith(fields ...string) *AnyBuilder
- func (draft *AnyBuilder) RequiredWithAll(fields ...string) *AnyBuilder
- func (draft *AnyBuilder) RequiredWithout(fields ...string) *AnyBuilder
- func (draft *AnyBuilder) Use(schema Schema[any]) *AnyBuilder
- func (draft *AnyBuilder) When(condition ConditionBuilderFunc, configure ...func(*AnyBuilder)) *AnyBuilder
- type AnyBuilderFunc
- type AnySchema
- type BoolBuilder
- func (rules *BoolBuilder[B]) Accepted() *BoolBuilder[B]
- func (draft *BoolBuilder[B]) Bail() *BoolBuilder[B]
- func (draft *BoolBuilder[B]) Check(fn func(context.Context, B) error) *BoolBuilder[B]
- func (rules *BoolBuilder[B]) Declined() *BoolBuilder[B]
- func (draft *BoolBuilder[B]) Default(value B) *BoolBuilder[B]
- func (draft *BoolBuilder[B]) Describe(text string) *BoolBuilder[B]
- func (draft *BoolBuilder[B]) EqField(field string) *BoolBuilder[B]
- func (draft *BoolBuilder[B]) ExcludeIf(configure ...ConditionBuilderFunc) *BoolBuilder[B]
- func (draft *BoolBuilder[B]) NeField(field string) *BoolBuilder[B]
- func (draft *BoolBuilder[B]) Normalize(fn func(B) B) *BoolBuilder[B]
- func (draft *BoolBuilder[B]) ProhibitedIf(configure ...ConditionBuilderFunc) *BoolBuilder[B]
- func (draft *BoolBuilder[B]) ProhibitedUnless(configure ...ConditionBuilderFunc) *BoolBuilder[B]
- func (draft *BoolBuilder[B]) Required() *BoolBuilder[B]
- func (draft *BoolBuilder[B]) RequiredIf(configure ...ConditionBuilderFunc) *BoolBuilder[B]
- func (draft *BoolBuilder[B]) RequiredUnless(configure ...ConditionBuilderFunc) *BoolBuilder[B]
- func (draft *BoolBuilder[B]) RequiredWith(fields ...string) *BoolBuilder[B]
- func (draft *BoolBuilder[B]) RequiredWithAll(fields ...string) *BoolBuilder[B]
- func (draft *BoolBuilder[B]) RequiredWithout(fields ...string) *BoolBuilder[B]
- func (draft *BoolBuilder[B]) Use(schema Schema[B]) *BoolBuilder[B]
- func (draft *BoolBuilder[B]) When(condition ConditionBuilderFunc, configure ...func(*BoolBuilder[B])) *BoolBuilder[B]
- type BoolBuilderFunc
- type BoolSchema
- type Catalog
- type ChildBuilderFunc
- type ConditionBuilder
- func (predicate *ConditionBuilder) Absent(path string) *ConditionBuilder
- func (predicate *ConditionBuilder) And(configure ...ConditionBuilderFunc) *ConditionBuilder
- func (predicate *ConditionBuilder) Contains[K comparable, V any](path string, match func(K, V) bool) *ConditionBuilder
- func (predicate *ConditionBuilder) CountWhere[K comparable, V any](path string, match func(K, V) bool, configure ...IntBuilderFunc[int]) *ConditionBuilder
- func (predicate *ConditionBuilder) Eq(path string, value any) *ConditionBuilder
- func (predicate *ConditionBuilder) Every[K comparable, V any](path string, match func(K, V) bool) *ConditionBuilder
- func (predicate *ConditionBuilder) Has[K comparable](path string, key K) *ConditionBuilder
- func (predicate *ConditionBuilder) HasAll[K comparable](path string, keys ...K) *ConditionBuilder
- func (predicate *ConditionBuilder) HasAny[K comparable](path string, keys ...K) *ConditionBuilder
- func (predicate *ConditionBuilder) If[T any](fn func(T) bool) *ConditionBuilder
- func (predicate *ConditionBuilder) In(path string, values ...any) *ConditionBuilder
- func (predicate *ConditionBuilder) Not(configure ...ConditionBuilderFunc) *ConditionBuilder
- func (predicate *ConditionBuilder) NotEq(path string, value any) *ConditionBuilder
- func (predicate *ConditionBuilder) NotIn(path string, values ...any) *ConditionBuilder
- func (predicate *ConditionBuilder) Or(configure ...ConditionBuilderFunc) *ConditionBuilder
- func (predicate *ConditionBuilder) Present(path string) *ConditionBuilder
- func (predicate *ConditionBuilder) UniqueBy[K comparable, V any, U comparable](path string, project func(K, V) U) *ConditionBuilder
- type ConditionBuilderFunc
- type Duration
- type EncodedSchema
- type Errors
- type FileBuilder
- func (draft *FileBuilder) Bail() *FileBuilder
- func (draft *FileBuilder) Check(fn func(context.Context, *multipart.FileHeader) error) *FileBuilder
- func (draft *FileBuilder) Describe(text string) *FileBuilder
- func (draft *FileBuilder) EqField(field string) *FileBuilder
- func (draft *FileBuilder) ExcludeIf(configure ...ConditionBuilderFunc) *FileBuilder
- func (rules *FileBuilder) Extensions(exts ...string) *FileBuilder
- func (rules *FileBuilder) Max(n int64) *FileBuilder
- func (rules *FileBuilder) Min(n int64) *FileBuilder
- func (draft *FileBuilder) NeField(field string) *FileBuilder
- func (draft *FileBuilder) Normalize(fn func(*multipart.FileHeader) *multipart.FileHeader) *FileBuilder
- func (draft *FileBuilder) ProhibitedIf(configure ...ConditionBuilderFunc) *FileBuilder
- func (draft *FileBuilder) ProhibitedUnless(configure ...ConditionBuilderFunc) *FileBuilder
- func (draft *FileBuilder) Required() *FileBuilder
- func (draft *FileBuilder) RequiredIf(configure ...ConditionBuilderFunc) *FileBuilder
- func (draft *FileBuilder) RequiredUnless(configure ...ConditionBuilderFunc) *FileBuilder
- func (draft *FileBuilder) RequiredWith(fields ...string) *FileBuilder
- func (draft *FileBuilder) RequiredWithAll(fields ...string) *FileBuilder
- func (draft *FileBuilder) RequiredWithout(fields ...string) *FileBuilder
- func (rules *FileBuilder) Types(types ...string) *FileBuilder
- func (draft *FileBuilder) Use(schema Schema[*multipart.FileHeader]) *FileBuilder
- func (draft *FileBuilder) When(condition ConditionBuilderFunc, configure ...func(*FileBuilder)) *FileBuilder
- type FileBuilderFunc
- type FileSchema
- type FloatBuilder
- func (number *FloatBuilder[N]) Abs() *FloatBuilder[N]
- func (draft *FloatBuilder[N]) Bail() *FloatBuilder[N]
- func (number *FloatBuilder[N]) Between(low, high N) *FloatBuilder[N]
- func (draft *FloatBuilder[N]) Check(fn func(context.Context, N) error) *FloatBuilder[N]
- func (number *FloatBuilder[N]) Clamp(low, high N) *FloatBuilder[N]
- func (draft *FloatBuilder[N]) Default(value N) *FloatBuilder[N]
- func (draft *FloatBuilder[N]) Describe(text string) *FloatBuilder[N]
- func (draft *FloatBuilder[N]) EqField(field string) *FloatBuilder[N]
- func (draft *FloatBuilder[N]) ExcludeIf(configure ...ConditionBuilderFunc) *FloatBuilder[N]
- func (number *FloatBuilder[N]) Gt(limit N) *FloatBuilder[N]
- func (number *FloatBuilder[N]) GtField(field string) *FloatBuilder[N]
- func (number *FloatBuilder[N]) Gte(limit N) *FloatBuilder[N]
- func (number *FloatBuilder[N]) GteField(field string) *FloatBuilder[N]
- func (number *FloatBuilder[N]) Lt(limit N) *FloatBuilder[N]
- func (number *FloatBuilder[N]) LtField(field string) *FloatBuilder[N]
- func (number *FloatBuilder[N]) Lte(limit N) *FloatBuilder[N]
- func (number *FloatBuilder[N]) LteField(field string) *FloatBuilder[N]
- func (number *FloatBuilder[N]) Max(limit N) *FloatBuilder[N]
- func (number *FloatBuilder[N]) Min(limit N) *FloatBuilder[N]
- func (number *FloatBuilder[N]) MultipleOf(factor N) *FloatBuilder[N]
- func (draft *FloatBuilder[N]) NeField(field string) *FloatBuilder[N]
- func (number *FloatBuilder[N]) NonNegative() *FloatBuilder[N]
- func (draft *FloatBuilder[N]) Normalize(fn func(N) N) *FloatBuilder[N]
- func (number *FloatBuilder[N]) NotOneOf(values ...N) *FloatBuilder[N]
- func (number *FloatBuilder[N]) OneOf(values ...N) *FloatBuilder[N]
- func (number *FloatBuilder[N]) Positive() *FloatBuilder[N]
- func (draft *FloatBuilder[N]) ProhibitedIf(configure ...ConditionBuilderFunc) *FloatBuilder[N]
- func (draft *FloatBuilder[N]) ProhibitedUnless(configure ...ConditionBuilderFunc) *FloatBuilder[N]
- func (draft *FloatBuilder[N]) Required() *FloatBuilder[N]
- func (draft *FloatBuilder[N]) RequiredIf(configure ...ConditionBuilderFunc) *FloatBuilder[N]
- func (draft *FloatBuilder[N]) RequiredUnless(configure ...ConditionBuilderFunc) *FloatBuilder[N]
- func (draft *FloatBuilder[N]) RequiredWith(fields ...string) *FloatBuilder[N]
- func (draft *FloatBuilder[N]) RequiredWithAll(fields ...string) *FloatBuilder[N]
- func (draft *FloatBuilder[N]) RequiredWithout(fields ...string) *FloatBuilder[N]
- func (number *FloatBuilder[N]) Round(places int) *FloatBuilder[N]
- func (draft *FloatBuilder[N]) Use(schema Schema[N]) *FloatBuilder[N]
- func (draft *FloatBuilder[N]) When(condition ConditionBuilderFunc, configure ...func(*FloatBuilder[N])) *FloatBuilder[N]
- type FloatBuilderFunc
- type FloatSchema
- type InferSchema
- type IntBuilder
- func (number *IntBuilder[N]) Abs() *IntBuilder[N]
- func (draft *IntBuilder[N]) Bail() *IntBuilder[N]
- func (number *IntBuilder[N]) Between(low, high N) *IntBuilder[N]
- func (draft *IntBuilder[N]) Check(fn func(context.Context, N) error) *IntBuilder[N]
- func (number *IntBuilder[N]) Clamp(low, high N) *IntBuilder[N]
- func (draft *IntBuilder[N]) Default(value N) *IntBuilder[N]
- func (draft *IntBuilder[N]) Describe(text string) *IntBuilder[N]
- func (draft *IntBuilder[N]) EqField(field string) *IntBuilder[N]
- func (draft *IntBuilder[N]) ExcludeIf(configure ...ConditionBuilderFunc) *IntBuilder[N]
- func (number *IntBuilder[N]) Gt(limit N) *IntBuilder[N]
- func (number *IntBuilder[N]) GtField(field string) *IntBuilder[N]
- func (number *IntBuilder[N]) Gte(limit N) *IntBuilder[N]
- func (number *IntBuilder[N]) GteField(field string) *IntBuilder[N]
- func (number *IntBuilder[N]) Lt(limit N) *IntBuilder[N]
- func (number *IntBuilder[N]) LtField(field string) *IntBuilder[N]
- func (number *IntBuilder[N]) Lte(limit N) *IntBuilder[N]
- func (number *IntBuilder[N]) LteField(field string) *IntBuilder[N]
- func (number *IntBuilder[N]) Max(limit N) *IntBuilder[N]
- func (number *IntBuilder[N]) Min(limit N) *IntBuilder[N]
- func (number *IntBuilder[N]) MultipleOf(factor N) *IntBuilder[N]
- func (draft *IntBuilder[N]) NeField(field string) *IntBuilder[N]
- func (number *IntBuilder[N]) NonNegative() *IntBuilder[N]
- func (draft *IntBuilder[N]) Normalize(fn func(N) N) *IntBuilder[N]
- func (number *IntBuilder[N]) NotOneOf(values ...N) *IntBuilder[N]
- func (number *IntBuilder[N]) OneOf(values ...N) *IntBuilder[N]
- func (number *IntBuilder[N]) Positive() *IntBuilder[N]
- func (draft *IntBuilder[N]) ProhibitedIf(configure ...ConditionBuilderFunc) *IntBuilder[N]
- func (draft *IntBuilder[N]) ProhibitedUnless(configure ...ConditionBuilderFunc) *IntBuilder[N]
- func (draft *IntBuilder[N]) Required() *IntBuilder[N]
- func (draft *IntBuilder[N]) RequiredIf(configure ...ConditionBuilderFunc) *IntBuilder[N]
- func (draft *IntBuilder[N]) RequiredUnless(configure ...ConditionBuilderFunc) *IntBuilder[N]
- func (draft *IntBuilder[N]) RequiredWith(fields ...string) *IntBuilder[N]
- func (draft *IntBuilder[N]) RequiredWithAll(fields ...string) *IntBuilder[N]
- func (draft *IntBuilder[N]) RequiredWithout(fields ...string) *IntBuilder[N]
- func (draft *IntBuilder[N]) Use(schema Schema[N]) *IntBuilder[N]
- func (draft *IntBuilder[N]) When(condition ConditionBuilderFunc, configure ...func(*IntBuilder[N])) *IntBuilder[N]
- type IntBuilderFunc
- type IntSchema
- type JSONSchema
- type JSONTypeProvider
- type MapBuilder
- func (draft *MapBuilder[K, V]) Bail() *MapBuilder[K, V]
- func (draft *MapBuilder[K, V]) Check(fn func(context.Context, map[K]V) error) *MapBuilder[K, V]
- func (entries *MapBuilder[K, V]) Contains(match func(K, V) bool) *MapBuilder[K, V]
- func (entries *MapBuilder[K, V]) CountWhere(match func(K, V) bool, configure ...IntBuilderFunc[int]) *MapBuilder[K, V]
- func (entries *MapBuilder[K, V]) Default(value map[K]V) *MapBuilder[K, V]
- func (draft *MapBuilder[K, V]) Describe(text string) *MapBuilder[K, V]
- func (draft *MapBuilder[K, V]) EqField(field string) *MapBuilder[K, V]
- func (entries *MapBuilder[K, V]) Every(match func(K, V) bool) *MapBuilder[K, V]
- func (draft *MapBuilder[K, V]) ExcludeIf(configure ...ConditionBuilderFunc) *MapBuilder[K, V]
- func (entries *MapBuilder[K, V]) Has(key K) *MapBuilder[K, V]
- func (entries *MapBuilder[K, V]) HasAll(keys ...K) *MapBuilder[K, V]
- func (entries *MapBuilder[K, V]) HasAny(keys ...K) *MapBuilder[K, V]
- func (entries *MapBuilder[K, V]) Keys[D any, P draftPointer[D]](configure ...ChildBuilderFunc[P]) *MapBuilder[K, V]
- func (entries *MapBuilder[K, V]) Len(size int) *MapBuilder[K, V]
- func (entries *MapBuilder[K, V]) Max(n int) *MapBuilder[K, V]
- func (entries *MapBuilder[K, V]) Min(n int) *MapBuilder[K, V]
- func (draft *MapBuilder[K, V]) NeField(field string) *MapBuilder[K, V]
- func (draft *MapBuilder[K, V]) Normalize(fn func(map[K]V) map[K]V) *MapBuilder[K, V]
- func (draft *MapBuilder[K, V]) ProhibitedIf(configure ...ConditionBuilderFunc) *MapBuilder[K, V]
- func (draft *MapBuilder[K, V]) ProhibitedUnless(configure ...ConditionBuilderFunc) *MapBuilder[K, V]
- func (draft *MapBuilder[K, V]) Required() *MapBuilder[K, V]
- func (draft *MapBuilder[K, V]) RequiredIf(configure ...ConditionBuilderFunc) *MapBuilder[K, V]
- func (draft *MapBuilder[K, V]) RequiredUnless(configure ...ConditionBuilderFunc) *MapBuilder[K, V]
- func (draft *MapBuilder[K, V]) RequiredWith(fields ...string) *MapBuilder[K, V]
- func (draft *MapBuilder[K, V]) RequiredWithAll(fields ...string) *MapBuilder[K, V]
- func (draft *MapBuilder[K, V]) RequiredWithout(fields ...string) *MapBuilder[K, V]
- func (entries *MapBuilder[K, V]) UniqueBy[U comparable](project func(K, V) U) *MapBuilder[K, V]
- func (draft *MapBuilder[K, V]) Use(schema Schema[map[K]V]) *MapBuilder[K, V]
- func (entries *MapBuilder[K, V]) Values[D any, P draftPointer[D]](configure ...ChildBuilderFunc[P]) *MapBuilder[K, V]
- func (draft *MapBuilder[K, V]) When(condition ConditionBuilderFunc, configure ...func(*MapBuilder[K, V])) *MapBuilder[K, V]
- type MapBuilderFunc
- type MapSchema
- type Messages
- type NamedBuilder
- type NamedBuilderFunc
- type NamedSchema
- type PtrBuilder
- func (draft *PtrBuilder[T]) Bail() *PtrBuilder[T]
- func (draft *PtrBuilder[T]) Check(fn func(context.Context, *T) error) *PtrBuilder[T]
- func (pointer *PtrBuilder[T]) Default(value T) *PtrBuilder[T]
- func (draft *PtrBuilder[T]) Describe(text string) *PtrBuilder[T]
- func (draft *PtrBuilder[T]) EqField(field string) *PtrBuilder[T]
- func (draft *PtrBuilder[T]) ExcludeIf(configure ...ConditionBuilderFunc) *PtrBuilder[T]
- func (draft *PtrBuilder[T]) NeField(field string) *PtrBuilder[T]
- func (draft *PtrBuilder[T]) Normalize(fn func(*T) *T) *PtrBuilder[T]
- func (draft *PtrBuilder[T]) ProhibitedIf(configure ...ConditionBuilderFunc) *PtrBuilder[T]
- func (draft *PtrBuilder[T]) ProhibitedUnless(configure ...ConditionBuilderFunc) *PtrBuilder[T]
- func (draft *PtrBuilder[T]) Required() *PtrBuilder[T]
- func (draft *PtrBuilder[T]) RequiredIf(configure ...ConditionBuilderFunc) *PtrBuilder[T]
- func (draft *PtrBuilder[T]) RequiredUnless(configure ...ConditionBuilderFunc) *PtrBuilder[T]
- func (draft *PtrBuilder[T]) RequiredWith(fields ...string) *PtrBuilder[T]
- func (draft *PtrBuilder[T]) RequiredWithAll(fields ...string) *PtrBuilder[T]
- func (draft *PtrBuilder[T]) RequiredWithout(fields ...string) *PtrBuilder[T]
- func (draft *PtrBuilder[T]) Use(schema Schema[*T]) *PtrBuilder[T]
- func (pointer *PtrBuilder[T]) Value[D any, P draftPointer[D]](configure ...ChildBuilderFunc[P]) *PtrBuilder[T]
- func (draft *PtrBuilder[T]) When(condition ConditionBuilderFunc, configure ...func(*PtrBuilder[T])) *PtrBuilder[T]
- type PtrBuilderFunc
- type PtrSchema
- type Schema
- type SliceBuilder
- func (draft *SliceBuilder[E]) Bail() *SliceBuilder[E]
- func (draft *SliceBuilder[E]) Check(fn func(context.Context, []E) error) *SliceBuilder[E]
- func (items *SliceBuilder[E]) Contains(match func(int, E) bool) *SliceBuilder[E]
- func (items *SliceBuilder[E]) CountWhere(match func(int, E) bool, configure ...IntBuilderFunc[int]) *SliceBuilder[E]
- func (items *SliceBuilder[E]) Dedupe() *SliceBuilder[E]
- func (items *SliceBuilder[E]) Default(value []E) *SliceBuilder[E]
- func (draft *SliceBuilder[E]) Describe(text string) *SliceBuilder[E]
- func (draft *SliceBuilder[E]) EqField(field string) *SliceBuilder[E]
- func (items *SliceBuilder[E]) Every(match func(int, E) bool) *SliceBuilder[E]
- func (draft *SliceBuilder[E]) ExcludeIf(configure ...ConditionBuilderFunc) *SliceBuilder[E]
- func (items *SliceBuilder[E]) Filter(keep func(int, E) bool) *SliceBuilder[E]
- func (items *SliceBuilder[E]) Len(n int) *SliceBuilder[E]
- func (items *SliceBuilder[E]) Max(n int) *SliceBuilder[E]
- func (items *SliceBuilder[E]) Min(n int) *SliceBuilder[E]
- func (draft *SliceBuilder[E]) NeField(field string) *SliceBuilder[E]
- func (draft *SliceBuilder[E]) Normalize(fn func([]E) []E) *SliceBuilder[E]
- func (draft *SliceBuilder[E]) ProhibitedIf(configure ...ConditionBuilderFunc) *SliceBuilder[E]
- func (draft *SliceBuilder[E]) ProhibitedUnless(configure ...ConditionBuilderFunc) *SliceBuilder[E]
- func (items *SliceBuilder[E]) Reject(drop func(int, E) bool) *SliceBuilder[E]
- func (items *SliceBuilder[E]) RejectZero() *SliceBuilder[E]
- func (draft *SliceBuilder[E]) Required() *SliceBuilder[E]
- func (draft *SliceBuilder[E]) RequiredIf(configure ...ConditionBuilderFunc) *SliceBuilder[E]
- func (draft *SliceBuilder[E]) RequiredUnless(configure ...ConditionBuilderFunc) *SliceBuilder[E]
- func (draft *SliceBuilder[E]) RequiredWith(fields ...string) *SliceBuilder[E]
- func (draft *SliceBuilder[E]) RequiredWithAll(fields ...string) *SliceBuilder[E]
- func (draft *SliceBuilder[E]) RequiredWithout(fields ...string) *SliceBuilder[E]
- func (items *SliceBuilder[E]) Sort(cmp func(E, E) int) *SliceBuilder[E]
- func (items *SliceBuilder[E]) Unique() *SliceBuilder[E]
- func (items *SliceBuilder[E]) UniqueBy[U comparable](project func(int, E) U) *SliceBuilder[E]
- func (draft *SliceBuilder[E]) Use(schema Schema[[]E]) *SliceBuilder[E]
- func (items *SliceBuilder[E]) Values[D any, P draftPointer[D]](configure ...ChildBuilderFunc[P]) *SliceBuilder[E]
- func (draft *SliceBuilder[E]) When(condition ConditionBuilderFunc, configure ...func(*SliceBuilder[E])) *SliceBuilder[E]
- type SliceBuilderFunc
- type SliceSchema
- type StringBuilder
- func (text *StringBuilder[S]) ASCII() *StringBuilder[S]
- func (text *StringBuilder[S]) Alpha() *StringBuilder[S]
- func (text *StringBuilder[S]) AlphaDash() *StringBuilder[S]
- func (text *StringBuilder[S]) AlphaNumeric() *StringBuilder[S]
- func (draft *StringBuilder[S]) Bail() *StringBuilder[S]
- func (draft *StringBuilder[S]) Check(fn func(context.Context, S) error) *StringBuilder[S]
- func (text *StringBuilder[S]) Contains(substring string) *StringBuilder[S]
- func (draft *StringBuilder[S]) Default(value S) *StringBuilder[S]
- func (draft *StringBuilder[S]) Describe(text string) *StringBuilder[S]
- func (text *StringBuilder[S]) Domain() *StringBuilder[S]
- func (text *StringBuilder[S]) Duration() *StringBuilder[S]
- func (text *StringBuilder[S]) Email() *StringBuilder[S]
- func (draft *StringBuilder[S]) EqField(field string) *StringBuilder[S]
- func (draft *StringBuilder[S]) ExcludeIf(configure ...ConditionBuilderFunc) *StringBuilder[S]
- func (text *StringBuilder[S]) IP() *StringBuilder[S]
- func (text *StringBuilder[S]) Len(n int) *StringBuilder[S]
- func (text *StringBuilder[S]) Lowercase() *StringBuilder[S]
- func (text *StringBuilder[S]) Max(n int) *StringBuilder[S]
- func (text *StringBuilder[S]) Min(n int) *StringBuilder[S]
- func (draft *StringBuilder[S]) NeField(field string) *StringBuilder[S]
- func (draft *StringBuilder[S]) Normalize(fn func(S) S) *StringBuilder[S]
- func (text *StringBuilder[S]) NotBlank() *StringBuilder[S]
- func (text *StringBuilder[S]) NotOneOf(values ...S) *StringBuilder[S]
- func (text *StringBuilder[S]) OneOf(values ...S) *StringBuilder[S]
- func (text *StringBuilder[S]) Prefix(prefix string) *StringBuilder[S]
- func (draft *StringBuilder[S]) ProhibitedIf(configure ...ConditionBuilderFunc) *StringBuilder[S]
- func (draft *StringBuilder[S]) ProhibitedUnless(configure ...ConditionBuilderFunc) *StringBuilder[S]
- func (text *StringBuilder[S]) Regex(pattern *regexp.Regexp) *StringBuilder[S]
- func (draft *StringBuilder[S]) Required() *StringBuilder[S]
- func (draft *StringBuilder[S]) RequiredIf(configure ...ConditionBuilderFunc) *StringBuilder[S]
- func (draft *StringBuilder[S]) RequiredUnless(configure ...ConditionBuilderFunc) *StringBuilder[S]
- func (draft *StringBuilder[S]) RequiredWith(fields ...string) *StringBuilder[S]
- func (draft *StringBuilder[S]) RequiredWithAll(fields ...string) *StringBuilder[S]
- func (draft *StringBuilder[S]) RequiredWithout(fields ...string) *StringBuilder[S]
- func (text *StringBuilder[S]) Suffix(suffix string) *StringBuilder[S]
- func (text *StringBuilder[S]) ToLower() *StringBuilder[S]
- func (text *StringBuilder[S]) ToUpper() *StringBuilder[S]
- func (text *StringBuilder[S]) Trim() *StringBuilder[S]
- func (text *StringBuilder[S]) TrimPrefix(prefix S) *StringBuilder[S]
- func (text *StringBuilder[S]) TrimSuffix(suffix S) *StringBuilder[S]
- func (text *StringBuilder[S]) Truncate(n int) *StringBuilder[S]
- func (text *StringBuilder[S]) URL(schemes ...string) *StringBuilder[S]
- func (text *StringBuilder[S]) UUID() *StringBuilder[S]
- func (text *StringBuilder[S]) Uppercase() *StringBuilder[S]
- func (draft *StringBuilder[S]) Use(schema Schema[S]) *StringBuilder[S]
- func (draft *StringBuilder[S]) When(condition ConditionBuilderFunc, configure ...func(*StringBuilder[S])) *StringBuilder[S]
- type StringBuilderFunc
- type StringSchema
- type StructBuilder
- func (draft *StructBuilder[T]) Bail() *StructBuilder[T]
- func (draft *StructBuilder[T]) Check(fn func(context.Context, T) error) *StructBuilder[T]
- func (draft *StructBuilder[T]) Default(value T) *StructBuilder[T]
- func (draft *StructBuilder[T]) Describe(text string) *StructBuilder[T]
- func (draft *StructBuilder[T]) EqField(field string) *StructBuilder[T]
- func (draft *StructBuilder[T]) ExcludeIf(configure ...ConditionBuilderFunc) *StructBuilder[T]
- func (object *StructBuilder[T]) Field[D any, P draftPointer[D]](name string, configure ...ChildBuilderFunc[P]) *StructBuilder[T]
- func (draft *StructBuilder[T]) NeField(field string) *StructBuilder[T]
- func (draft *StructBuilder[T]) Normalize(fn func(T) T) *StructBuilder[T]
- func (draft *StructBuilder[T]) ProhibitedIf(configure ...ConditionBuilderFunc) *StructBuilder[T]
- func (draft *StructBuilder[T]) ProhibitedUnless(configure ...ConditionBuilderFunc) *StructBuilder[T]
- func (draft *StructBuilder[T]) Required() *StructBuilder[T]
- func (draft *StructBuilder[T]) RequiredIf(configure ...ConditionBuilderFunc) *StructBuilder[T]
- func (draft *StructBuilder[T]) RequiredUnless(configure ...ConditionBuilderFunc) *StructBuilder[T]
- func (draft *StructBuilder[T]) RequiredWith(fields ...string) *StructBuilder[T]
- func (draft *StructBuilder[T]) RequiredWithAll(fields ...string) *StructBuilder[T]
- func (draft *StructBuilder[T]) RequiredWithout(fields ...string) *StructBuilder[T]
- func (object *StructBuilder[T]) Use(schema Schema[T]) *StructBuilder[T]
- func (draft *StructBuilder[T]) When(condition ConditionBuilderFunc, configure ...func(*StructBuilder[T])) *StructBuilder[T]
- type StructBuilderFunc
- type StructSchema
- type TextBuilder
- func (draft *TextBuilder[T]) Bail() *TextBuilder[T]
- func (draft *TextBuilder[T]) Check(fn func(context.Context, T) error) *TextBuilder[T]
- func (draft *TextBuilder[T]) Default(value T) *TextBuilder[T]
- func (draft *TextBuilder[T]) Describe(text string) *TextBuilder[T]
- func (draft *TextBuilder[T]) EqField(field string) *TextBuilder[T]
- func (draft *TextBuilder[T]) ExcludeIf(configure ...ConditionBuilderFunc) *TextBuilder[T]
- func (draft *TextBuilder[T]) NeField(field string) *TextBuilder[T]
- func (draft *TextBuilder[T]) Normalize(fn func(T) T) *TextBuilder[T]
- func (draft *TextBuilder[T]) ProhibitedIf(configure ...ConditionBuilderFunc) *TextBuilder[T]
- func (draft *TextBuilder[T]) ProhibitedUnless(configure ...ConditionBuilderFunc) *TextBuilder[T]
- func (draft *TextBuilder[T]) Required() *TextBuilder[T]
- func (draft *TextBuilder[T]) RequiredIf(configure ...ConditionBuilderFunc) *TextBuilder[T]
- func (draft *TextBuilder[T]) RequiredUnless(configure ...ConditionBuilderFunc) *TextBuilder[T]
- func (draft *TextBuilder[T]) RequiredWith(fields ...string) *TextBuilder[T]
- func (draft *TextBuilder[T]) RequiredWithAll(fields ...string) *TextBuilder[T]
- func (draft *TextBuilder[T]) RequiredWithout(fields ...string) *TextBuilder[T]
- func (draft *TextBuilder[T]) Use(schema Schema[T]) *TextBuilder[T]
- func (draft *TextBuilder[T]) When(condition ConditionBuilderFunc, configure ...func(*TextBuilder[T])) *TextBuilder[T]
- type TextBuilderFunc
- type TextSchema
- type TimeBuilder
- func (moment *TimeBuilder) After(limit time.Time) *TimeBuilder
- func (moment *TimeBuilder) AfterField(field string) *TimeBuilder
- func (draft *TimeBuilder) Bail() *TimeBuilder
- func (moment *TimeBuilder) Before(limit time.Time) *TimeBuilder
- func (moment *TimeBuilder) BeforeField(field string) *TimeBuilder
- func (moment *TimeBuilder) Between(low, high time.Time) *TimeBuilder
- func (draft *TimeBuilder) Check(fn func(context.Context, time.Time) error) *TimeBuilder
- func (draft *TimeBuilder) Default(value time.Time) *TimeBuilder
- func (draft *TimeBuilder) Describe(text string) *TimeBuilder
- func (draft *TimeBuilder) EqField(field string) *TimeBuilder
- func (draft *TimeBuilder) ExcludeIf(configure ...ConditionBuilderFunc) *TimeBuilder
- func (moment *TimeBuilder) Future() *TimeBuilder
- func (draft *TimeBuilder) NeField(field string) *TimeBuilder
- func (draft *TimeBuilder) Normalize(fn func(time.Time) time.Time) *TimeBuilder
- func (moment *TimeBuilder) Past() *TimeBuilder
- func (draft *TimeBuilder) ProhibitedIf(configure ...ConditionBuilderFunc) *TimeBuilder
- func (draft *TimeBuilder) ProhibitedUnless(configure ...ConditionBuilderFunc) *TimeBuilder
- func (draft *TimeBuilder) Required() *TimeBuilder
- func (draft *TimeBuilder) RequiredIf(configure ...ConditionBuilderFunc) *TimeBuilder
- func (draft *TimeBuilder) RequiredUnless(configure ...ConditionBuilderFunc) *TimeBuilder
- func (draft *TimeBuilder) RequiredWith(fields ...string) *TimeBuilder
- func (draft *TimeBuilder) RequiredWithAll(fields ...string) *TimeBuilder
- func (draft *TimeBuilder) RequiredWithout(fields ...string) *TimeBuilder
- func (moment *TimeBuilder) UTC() *TimeBuilder
- func (draft *TimeBuilder) Use(schema Schema[time.Time]) *TimeBuilder
- func (draft *TimeBuilder) When(condition ConditionBuilderFunc, configure ...func(*TimeBuilder)) *TimeBuilder
- type TimeBuilderFunc
- type TimeSchema
- type UintBuilder
- func (draft *UintBuilder[N]) Bail() *UintBuilder[N]
- func (number *UintBuilder[N]) Between(low, high N) *UintBuilder[N]
- func (draft *UintBuilder[N]) Check(fn func(context.Context, N) error) *UintBuilder[N]
- func (number *UintBuilder[N]) Clamp(low, high N) *UintBuilder[N]
- func (draft *UintBuilder[N]) Default(value N) *UintBuilder[N]
- func (draft *UintBuilder[N]) Describe(text string) *UintBuilder[N]
- func (draft *UintBuilder[N]) EqField(field string) *UintBuilder[N]
- func (draft *UintBuilder[N]) ExcludeIf(configure ...ConditionBuilderFunc) *UintBuilder[N]
- func (number *UintBuilder[N]) Gt(limit N) *UintBuilder[N]
- func (number *UintBuilder[N]) GtField(field string) *UintBuilder[N]
- func (number *UintBuilder[N]) Gte(limit N) *UintBuilder[N]
- func (number *UintBuilder[N]) GteField(field string) *UintBuilder[N]
- func (number *UintBuilder[N]) Lt(limit N) *UintBuilder[N]
- func (number *UintBuilder[N]) LtField(field string) *UintBuilder[N]
- func (number *UintBuilder[N]) Lte(limit N) *UintBuilder[N]
- func (number *UintBuilder[N]) LteField(field string) *UintBuilder[N]
- func (number *UintBuilder[N]) Max(limit N) *UintBuilder[N]
- func (number *UintBuilder[N]) Min(limit N) *UintBuilder[N]
- func (number *UintBuilder[N]) MultipleOf(factor N) *UintBuilder[N]
- func (draft *UintBuilder[N]) NeField(field string) *UintBuilder[N]
- func (number *UintBuilder[N]) NonNegative() *UintBuilder[N]
- func (draft *UintBuilder[N]) Normalize(fn func(N) N) *UintBuilder[N]
- func (number *UintBuilder[N]) NotOneOf(values ...N) *UintBuilder[N]
- func (number *UintBuilder[N]) OneOf(values ...N) *UintBuilder[N]
- func (number *UintBuilder[N]) Positive() *UintBuilder[N]
- func (draft *UintBuilder[N]) ProhibitedIf(configure ...ConditionBuilderFunc) *UintBuilder[N]
- func (draft *UintBuilder[N]) ProhibitedUnless(configure ...ConditionBuilderFunc) *UintBuilder[N]
- func (draft *UintBuilder[N]) Required() *UintBuilder[N]
- func (draft *UintBuilder[N]) RequiredIf(configure ...ConditionBuilderFunc) *UintBuilder[N]
- func (draft *UintBuilder[N]) RequiredUnless(configure ...ConditionBuilderFunc) *UintBuilder[N]
- func (draft *UintBuilder[N]) RequiredWith(fields ...string) *UintBuilder[N]
- func (draft *UintBuilder[N]) RequiredWithAll(fields ...string) *UintBuilder[N]
- func (draft *UintBuilder[N]) RequiredWithout(fields ...string) *UintBuilder[N]
- func (draft *UintBuilder[N]) Use(schema Schema[N]) *UintBuilder[N]
- func (draft *UintBuilder[N]) When(condition ConditionBuilderFunc, configure ...func(*UintBuilder[N])) *UintBuilder[N]
- type UintBuilderFunc
- type UintSchema
- type Violation
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrEncodedJSON = faults.ErrEncodedJSON
ErrEncodedJSON identifies malformed instance JSON, including duplicate object names and trailing documents. Its message contains no document text. Schema syntax failures instead wrap ErrInvalidSchema. Neither error is an Errors value. Adapters must not send raw validation errors to an untrusted client: schema violations contain JSON Pointers, which can include private names.
Example:
check, err := validate.FromJSONSchemaStrict([]byte(`true`))
if err != nil {
return err
}
err = check.Validate(context.Background(), []byte(`{"name":1,"name":2}`))
if errors.Is(err, validate.ErrEncodedJSON) {
return errors.New("output is not valid JSON")
}
return err
var ErrEncodedLimit = faults.ErrEncodedLimit
ErrEncodedLimit identifies a resource refusal, not a schema violation. Both compilation and validation can wrap it. No operation approximates a number or accepts an incomplete traversal when a limit is reached. Adapters should classify this as an internal/resource failure, not invalid output.
Example:
check, err := validate.FromJSONSchemaStrict([]byte(`true`))
if err != nil {
return err
}
err = check.Validate(context.Background(), []byte(`1e4097`))
if errors.Is(err, validate.ErrEncodedLimit) {
return errors.New("output validation exceeded its resource budget")
}
return err
var ErrInvalidSchema = faults.ErrInvalidSchema
ErrInvalidSchema is wrapped by the panic value raised when a schema is built incorrectly, for example a Struct registration that names a missing field. The message lists every problem found.
Example:
defer func() {
if err, ok := recover().(error); ok && errors.Is(err, validate.ErrInvalidSchema) {
fmt.Println(err)
}
}()
validate.Struct[string]() // Struct requires a supported struct type.
Functions ¶
func At ¶
At reports a validation failure at a sibling field from a Struct Check function. The field is a Go field name, as in StructBuilder.Field. An unknown field makes validation fail with an error wrapping ErrInvalidSchema. Parameters follow Fail's copying limits: supported containers are captured now and detached again for each reported violation; arbitrary objects remain shared. A nil params map remains nil.
Example:
type Booking struct {
Start, End int
}
schema := validate.Struct(func(object *validate.StructBuilder[Booking]) {
object.Field("End", func(number *validate.IntBuilder[int]) {
})
object.Check(func(_ context.Context, value Booking) error {
if value.End < value.Start {
return validate.At("End", "order", nil)
}
return nil
})
})
err := schema.Validate(context.Background(), Booking{
Start: 2,
End: 1,
})
if err != nil {
fmt.Println(err)
}
func Fail ¶
Fail reports a validation failure from a Check function. The engine records it as a violation with the given code at the checked value. Any other error returned from a Check passes through unchanged. The returned error may be reused across checks and schema executions; each reported violation receives independent parameter containers.
Fail snapshots slices, arrays and string-keyed maps recursively, including containers reached through interfaces. Named container and string-key types, scalar types and nil-versus-empty distinctions are preserved. All other values are retained without traversing struct fields, following pointers or inspecting maps with non-string keys. Opaque native objects, functions and captures remain application-owned. This is container copying, not a general object deep copy or JSON conversion.
params must be acyclic along copied containers; cycles are not detected. Values must be serializable to JSON if the violations will be encoded; Fail does not validate or encode them and never invokes marshaling methods. A nil params map remains nil.
Example:
allowed := []int{3, 5}
failure := validate.Fail("reserved", map[string]any{"allowed": allowed})
allowed[0] = 99 // Does not change the captured parameter.
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.Check(func(_ context.Context, value string) error {
return failure
})
})
_, err := schema.Parse(context.Background(), "admin")
if failures, ok := errors.AsType[validate.Errors](err); ok {
fmt.Println(failures[""][0].Params["allowed"]) // [3 5]
}
func LocaleFromContext ¶
LocaleFromContext returns the locale stored by NewLocaleContext. The boolean is false when the context carries no locale.
func NewCatalogContext ¶
NewCatalogContext returns a context that renders violation messages from catalog. Locales missing from the catalog fall back to the built-in English messages. It snapshots the locale registry and each message map; callers may edit their original catalog after the call returns. Nil maps remain nil and retain the normal English fallback.
Example:
catalog := validate.Catalog{
Default: "en",
Locales: map[string]validate.Messages{"en": {"required": "please enter a value"}},
}
ctx := validate.NewCatalogContext(context.Background(), catalog)
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.Required()
})
if _, err := schema.Parse(ctx, ""); err != nil {
fmt.Println(err)
}
Example ¶
ExampleNewCatalogContext renders messages in another language.
package main
import (
"context"
"errors"
"fmt"
"arkoren.dev/foundation/validate"
)
func main() {
catalog := validate.Catalog{
Default: "en",
Locales: map[string]validate.Messages{
"es": {"string.min": "debe tener al menos {min} caracteres"},
},
}
ctx := validate.NewCatalogContext(context.Background(), catalog)
ctx = validate.NewLocaleContext(ctx, "es-MX")
err := validate.String(func(value *validate.StringBuilder[string]) {
value.Min(3)
}).Validate(ctx, "ab")
errs, ok := errors.AsType[validate.Errors](err)
if !ok {
fmt.Println(err)
return
}
fmt.Println(errs[""][0].Message)
}
Output: debe tener al menos 3 caracteres
func NewClockContext ¶
NewClockContext returns a context whose Future and Past rules read the current time from now instead of time.Now. Tests use it to pin time.
Types ¶
type AnyBuilder ¶
type AnyBuilder struct {
// contains filtered or unexported fields
}
AnyBuilder configures a detached AnySchema during construction. Settings return the same draft. Retaining a draft cannot change a schema; concurrent mutation of a draft is not supported.
Example:
var configure validate.AnyBuilderFunc = func(rules *validate.AnyBuilder) {
rules.Required()
}
_ = configure
func (*AnyBuilder) Bail ¶
func (draft *AnyBuilder) Bail() *AnyBuilder
Bail stops checking this value at its first failure. By default every failure is reported.
Example:
type Value struct {
Name string
}
type Form struct {
Value any
Peer any
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.AnyBuilder) {
rules.Bail()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*AnyBuilder) Check ¶
func (draft *AnyBuilder) Check(fn func(context.Context, any) error) *AnyBuilder
Check adds a custom rule that runs only for present values. Return Fail (or At in a Struct check) to report a violation; any other error aborts validation and is returned to the caller unchanged.
Example:
type Value struct {
Name string
}
type Form struct {
Value any
Peer any
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.AnyBuilder) {
rules.Check(func(_ context.Context, value any) error {
return nil
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*AnyBuilder) Default ¶
func (draft *AnyBuilder) Default(value any) *AnyBuilder
Default sets the value Parse uses when the prepared input is absent. Registered defaults are checked while a Struct is built; standalone defaults are checked by execution, not metadata export. Input normalizers run before default selection and do not run again on the selected default. Arbitrary default objects retain application ownership. Default cannot be combined with Required.
Example:
type Value struct {
Name string
}
type Form struct {
Value any
Peer any
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.AnyBuilder) {
rules.Default("Ada")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*AnyBuilder) Describe ¶
func (draft *AnyBuilder) Describe(text string) *AnyBuilder
Describe sets the human-readable description that JSONSchema renders as "description". It does not affect validation. Use it for field and tool descriptions.
Example:
type Value struct {
Name string
}
type Form struct {
Value any
Peer any
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.AnyBuilder) {
rules.Describe("A display value")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*AnyBuilder) EqField ¶
func (draft *AnyBuilder) EqField(field string) *AnyBuilder
EqField requires the value to equal the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value any
Peer any
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.AnyBuilder) {
rules.EqField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*AnyBuilder) ExcludeIf ¶
func (draft *AnyBuilder) ExcludeIf(configure ...ConditionBuilderFunc) *AnyBuilder
ExcludeIf treats the value as absent, and clears it, when the conditions hold. Later ordinary value constraints skip absence, but later presence constraints still observe it and can report violations. Unconditional preparation may already have run before this rule is evaluated.
Example:
type Value struct {
Name string
}
type Form struct {
Value any
Peer any
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.AnyBuilder) {
rules.ExcludeIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*AnyBuilder) NeField ¶
func (draft *AnyBuilder) NeField(field string) *AnyBuilder
NeField requires the value to differ from the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value any
Peer any
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.AnyBuilder) {
rules.NeField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*AnyBuilder) Normalize ¶
func (draft *AnyBuilder) Normalize(fn func(any) any) *AnyBuilder
Normalize adds a custom normalizer. It runs before the presence check, Default and every rule, in the order written among the normalizers. It must return the value it is given or a new one, and must not modify its argument. Normalize cannot be used on Map key schemas.
Example:
type Value struct {
Name string
}
type Form struct {
Value any
Peer any
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.AnyBuilder) {
rules.Normalize(func(value any) any {
return value
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*AnyBuilder) ProhibitedIf ¶
func (draft *AnyBuilder) ProhibitedIf(configure ...ConditionBuilderFunc) *AnyBuilder
ProhibitedIf fails when the value is present and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value any
Peer any
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.AnyBuilder) {
rules.ProhibitedIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*AnyBuilder) ProhibitedUnless ¶
func (draft *AnyBuilder) ProhibitedUnless(configure ...ConditionBuilderFunc) *AnyBuilder
ProhibitedUnless fails when the value is present and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value any
Peer any
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.AnyBuilder) {
rules.ProhibitedUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*AnyBuilder) Required ¶
func (draft *AnyBuilder) Required() *AnyBuilder
Required fails when the value is absent. Absent means zero, or nil for pointers, slices and maps. It cannot be combined with Default.
Example:
type Value struct {
Name string
}
type Form struct {
Value any
Peer any
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.AnyBuilder) {
rules.Required()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*AnyBuilder) RequiredIf ¶
func (draft *AnyBuilder) RequiredIf(configure ...ConditionBuilderFunc) *AnyBuilder
RequiredIf fails when the value is absent and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value any
Peer any
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.AnyBuilder) {
rules.RequiredIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*AnyBuilder) RequiredUnless ¶
func (draft *AnyBuilder) RequiredUnless(configure ...ConditionBuilderFunc) *AnyBuilder
RequiredUnless fails when the value is absent and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value any
Peer any
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.AnyBuilder) {
rules.RequiredUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*AnyBuilder) RequiredWith ¶
func (draft *AnyBuilder) RequiredWith(fields ...string) *AnyBuilder
RequiredWith fails when the value is absent and any of the sibling fields is present.
Example:
type Value struct {
Name string
}
type Form struct {
Value any
Peer any
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.AnyBuilder) {
rules.RequiredWith("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*AnyBuilder) RequiredWithAll ¶
func (draft *AnyBuilder) RequiredWithAll(fields ...string) *AnyBuilder
RequiredWithAll fails when the value is absent and all of the sibling fields are present.
Example:
type Value struct {
Name string
}
type Form struct {
Value any
Peer any
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.AnyBuilder) {
rules.RequiredWithAll("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*AnyBuilder) RequiredWithout ¶
func (draft *AnyBuilder) RequiredWithout(fields ...string) *AnyBuilder
RequiredWithout fails when the value is absent and any of the sibling fields is absent.
Example:
type Value struct {
Name string
}
type Form struct {
Value any
Peer any
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.AnyBuilder) {
rules.RequiredWithout("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*AnyBuilder) Use ¶
func (draft *AnyBuilder) Use(schema Schema[any]) *AnyBuilder
Use adds rules from the same published schema role, as a value or nonnil pointer, before subsequent local settings. InferSchema contributes type-only documentation, not validation or missing child definitions. FromJSONSchema provides a separate decoded-JSON API, not a Schema value accepted here. Other schema roles are rejected even when their value type matches, because importing only their base could lose child rules. Schema-level rules accumulate. Overlapping child definitions are construction errors, and later local child callbacks cannot replace an imported child. Ptr permits an unconstrained scalar adapter to yield to a shared pointee. The source remains immutable. Typed nil pointers wrap ErrInvalidSchema.
Example:
var configure validate.AnyBuilderFunc = func(rules *validate.AnyBuilder) {
rules.Use(validate.Any())
}
_ = configure
func (*AnyBuilder) When ¶
func (draft *AnyBuilder) When(condition ConditionBuilderFunc, configure ...func(*AnyBuilder)) *AnyBuilder
When applies additional rules when the condition holds for the enclosing struct. The extra schema runs in place, in the order written, and sees defaults and exclusions like the rest of the chain.
Example:
type Value struct {
Name string
}
type Form struct {
Value any
Peer any
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.AnyBuilder) {
rules.When(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
}, func(selected *validate.AnyBuilder) {
selected.Required()
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
type AnyBuilderFunc ¶
type AnyBuilderFunc = func(*AnyBuilder)
AnyBuilderFunc edits one temporary AnyBuilder. Constructors invoke callbacks once, synchronously in order; a nil supplied callback panics.
Example:
var configure validate.AnyBuilderFunc = func(rules *validate.AnyBuilder) {
rules.Required()
}
_ = configure
type AnySchema ¶
type AnySchema struct {
// contains filtered or unexported fields
}
AnySchema validates values of the empty interface type. Create one with Any. A nil value is absent and every other value is present, whatever it holds, so Required means "not nil".
Example:
schema := validate.Any(func(value *validate.AnyBuilder) {
value.Required()
})
if err := schema.Validate(context.Background(), "created"); err != nil { panic(err) }
func Any ¶
func Any(configure ...AnyBuilderFunc) AnySchema
Any returns a schema that accepts any value, for fields declared as any or as an interface that the schema should not constrain. Its JSON Schema is {} (every JSON value is valid), plus the description and default when set. Struct matches it only against fields of exactly type any; use AnyBuilder.Check to inspect the dynamic value. Callbacks run once in order and retained drafts cannot change the published schema.
Example:
type Event struct {
Payload any
}
var event = validate.Struct[Event](func(object *validate.StructBuilder[Event]) {
object.Field("Payload", func(payload *validate.AnyBuilder) {
payload.Required().Describe("Event-specific data")
})
})
err := event.Validate(context.Background(), Event{
Payload: "created",
})
if err != nil {
panic(err)
}
func (AnySchema) JSONSchema ¶
JSONSchema renders this schema's supported JSON Schema constraints. Runtime-only rules remain enforced by Parse and Validate; invalid schema definitions or values that JSON cannot encode return an error. As with StringSchema.JSONSchema, definition checks never execute validation callbacks; recorded construction errors wrap ErrInvalidSchema.
Example:
schema := validate.Any()
document, err := schema.JSONSchema()
if err != nil {
panic(err)
}
_ = document
func (AnySchema) Parse ¶
Parse checks the input and returns its normalized, defaulted result. It copies storage before applying schema changes and returns the zero value with Errors or a custom Check error when validation fails.
Example:
schema := validate.Any()
value, err := schema.Parse(context.Background(), "Ada")
if err != nil {
panic(err)
}
_ = value
func (AnySchema) Validate ¶
Validate checks the input using the same preparation and rules as Parse, without returning the prepared value. It returns nil, Errors, or a custom Check error; caller-owned input is not modified.
Example:
schema := validate.Any()
if err := schema.Validate(context.Background(), "Ada"); err != nil {
panic(err)
}
type BoolBuilder ¶
type BoolBuilder[B ~bool] struct { // contains filtered or unexported fields }
BoolBuilder configures a detached BoolSchema during construction. Settings return the same draft. Retaining a draft cannot change a schema; concurrent mutation of a draft is not supported.
Example:
var configure validate.BoolBuilderFunc[bool] = func(rules *validate.BoolBuilder[bool]) {
rules.Required()
}
_ = configure
func (*BoolBuilder[B]) Accepted ¶
func (rules *BoolBuilder[B]) Accepted() *BoolBuilder[B]
Accepted requires the value to be true, such as a terms checkbox. A false value fails, even though false is otherwise absent.
Example:
schema := validate.Bool(func(value *validate.BoolBuilder[bool]) {
value.Accepted()
})
if err := schema.Validate(context.Background(), true); err != nil {
panic(err)
}
func (*BoolBuilder[B]) Bail ¶
func (draft *BoolBuilder[B]) Bail() *BoolBuilder[B]
Bail stops checking this value at its first failure. By default every failure is reported.
Example:
type Value struct {
Name string
}
type Form struct {
Value bool
Peer bool
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.BoolBuilder[bool]) {
rules.Bail()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*BoolBuilder[B]) Check ¶
func (draft *BoolBuilder[B]) Check(fn func(context.Context, B) error) *BoolBuilder[B]
Check adds a custom rule that runs only for present values. Return Fail (or At in a Struct check) to report a violation; any other error aborts validation and is returned to the caller unchanged.
Example:
type Value struct {
Name string
}
type Form struct {
Value bool
Peer bool
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.BoolBuilder[bool]) {
rules.Check(func(_ context.Context, value bool) error {
return nil
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*BoolBuilder[B]) Declined ¶
func (rules *BoolBuilder[B]) Declined() *BoolBuilder[B]
Declined requires the value to be false. True fails.
Example:
schema := validate.Bool(func(value *validate.BoolBuilder[bool]) {
value.Declined()
})
if err := schema.Validate(context.Background(), false); err != nil {
panic(err)
}
func (*BoolBuilder[B]) Default ¶
func (draft *BoolBuilder[B]) Default(value B) *BoolBuilder[B]
Default sets the value Parse uses when the prepared input is absent. Registered defaults are checked while a Struct is built; standalone defaults are checked by execution, not metadata export. Input normalizers run before default selection and do not run again on the selected default. Arbitrary default objects retain application ownership. Default cannot be combined with Required.
Example:
type Value struct {
Name string
}
type Form struct {
Value bool
Peer bool
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.BoolBuilder[bool]) {
rules.Default(true)
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*BoolBuilder[B]) Describe ¶
func (draft *BoolBuilder[B]) Describe(text string) *BoolBuilder[B]
Describe sets the human-readable description that JSONSchema renders as "description". It does not affect validation. Use it for field and tool descriptions.
Example:
type Value struct {
Name string
}
type Form struct {
Value bool
Peer bool
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.BoolBuilder[bool]) {
rules.Describe("A display value")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*BoolBuilder[B]) EqField ¶
func (draft *BoolBuilder[B]) EqField(field string) *BoolBuilder[B]
EqField requires the value to equal the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value bool
Peer bool
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.BoolBuilder[bool]) {
rules.EqField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*BoolBuilder[B]) ExcludeIf ¶
func (draft *BoolBuilder[B]) ExcludeIf(configure ...ConditionBuilderFunc) *BoolBuilder[B]
ExcludeIf treats the value as absent, and clears it, when the conditions hold. Later ordinary value constraints skip absence, but later presence constraints still observe it and can report violations. Unconditional preparation may already have run before this rule is evaluated.
Example:
type Value struct {
Name string
}
type Form struct {
Value bool
Peer bool
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.BoolBuilder[bool]) {
rules.ExcludeIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*BoolBuilder[B]) NeField ¶
func (draft *BoolBuilder[B]) NeField(field string) *BoolBuilder[B]
NeField requires the value to differ from the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value bool
Peer bool
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.BoolBuilder[bool]) {
rules.NeField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*BoolBuilder[B]) Normalize ¶
func (draft *BoolBuilder[B]) Normalize(fn func(B) B) *BoolBuilder[B]
Normalize adds a custom normalizer. It runs before the presence check, Default and every rule, in the order written among the normalizers. It must return the value it is given or a new one, and must not modify its argument. Normalize cannot be used on Map key schemas.
Example:
type Value struct {
Name string
}
type Form struct {
Value bool
Peer bool
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.BoolBuilder[bool]) {
rules.Normalize(func(value bool) bool {
return value
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*BoolBuilder[B]) ProhibitedIf ¶
func (draft *BoolBuilder[B]) ProhibitedIf(configure ...ConditionBuilderFunc) *BoolBuilder[B]
ProhibitedIf fails when the value is present and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value bool
Peer bool
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.BoolBuilder[bool]) {
rules.ProhibitedIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*BoolBuilder[B]) ProhibitedUnless ¶
func (draft *BoolBuilder[B]) ProhibitedUnless(configure ...ConditionBuilderFunc) *BoolBuilder[B]
ProhibitedUnless fails when the value is present and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value bool
Peer bool
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.BoolBuilder[bool]) {
rules.ProhibitedUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*BoolBuilder[B]) Required ¶
func (draft *BoolBuilder[B]) Required() *BoolBuilder[B]
Required fails when the value is absent. Absent means zero, or nil for pointers, slices and maps. It cannot be combined with Default.
Example:
type Value struct {
Name string
}
type Form struct {
Value bool
Peer bool
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.BoolBuilder[bool]) {
rules.Required()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*BoolBuilder[B]) RequiredIf ¶
func (draft *BoolBuilder[B]) RequiredIf(configure ...ConditionBuilderFunc) *BoolBuilder[B]
RequiredIf fails when the value is absent and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value bool
Peer bool
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.BoolBuilder[bool]) {
rules.RequiredIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*BoolBuilder[B]) RequiredUnless ¶
func (draft *BoolBuilder[B]) RequiredUnless(configure ...ConditionBuilderFunc) *BoolBuilder[B]
RequiredUnless fails when the value is absent and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value bool
Peer bool
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.BoolBuilder[bool]) {
rules.RequiredUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*BoolBuilder[B]) RequiredWith ¶
func (draft *BoolBuilder[B]) RequiredWith(fields ...string) *BoolBuilder[B]
RequiredWith fails when the value is absent and any of the sibling fields is present.
Example:
type Value struct {
Name string
}
type Form struct {
Value bool
Peer bool
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.BoolBuilder[bool]) {
rules.RequiredWith("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*BoolBuilder[B]) RequiredWithAll ¶
func (draft *BoolBuilder[B]) RequiredWithAll(fields ...string) *BoolBuilder[B]
RequiredWithAll fails when the value is absent and all of the sibling fields are present.
Example:
type Value struct {
Name string
}
type Form struct {
Value bool
Peer bool
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.BoolBuilder[bool]) {
rules.RequiredWithAll("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*BoolBuilder[B]) RequiredWithout ¶
func (draft *BoolBuilder[B]) RequiredWithout(fields ...string) *BoolBuilder[B]
RequiredWithout fails when the value is absent and any of the sibling fields is absent.
Example:
type Value struct {
Name string
}
type Form struct {
Value bool
Peer bool
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.BoolBuilder[bool]) {
rules.RequiredWithout("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*BoolBuilder[B]) Use ¶
func (draft *BoolBuilder[B]) Use(schema Schema[B]) *BoolBuilder[B]
Use adds rules from the same published schema role, as a value or nonnil pointer, before subsequent local settings. InferSchema contributes type-only documentation, not validation or missing child definitions. FromJSONSchema provides a separate decoded-JSON API, not a Schema value accepted here. Other schema roles are rejected even when their value type matches, because importing only their base could lose child rules. Schema-level rules accumulate. Overlapping child definitions are construction errors, and later local child callbacks cannot replace an imported child. Ptr permits an unconstrained scalar adapter to yield to a shared pointee. The source remains immutable. Typed nil pointers wrap ErrInvalidSchema.
Example:
var configure validate.BoolBuilderFunc[bool] = func(rules *validate.BoolBuilder[bool]) {
rules.Use(validate.Bool[bool]())
}
_ = configure
func (*BoolBuilder[B]) When ¶
func (draft *BoolBuilder[B]) When(condition ConditionBuilderFunc, configure ...func(*BoolBuilder[B])) *BoolBuilder[B]
When applies additional rules when the condition holds for the enclosing struct. The extra schema runs in place, in the order written, and sees defaults and exclusions like the rest of the chain.
Example:
type Value struct {
Name string
}
type Form struct {
Value bool
Peer bool
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.BoolBuilder[bool]) {
rules.When(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
}, func(selected *validate.BoolBuilder[bool]) {
selected.Required()
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
type BoolBuilderFunc ¶
type BoolBuilderFunc[B ~bool] = func(*BoolBuilder[B])
BoolBuilderFunc edits one temporary BoolBuilder. Constructors invoke callbacks once, synchronously in order; a nil supplied callback panics.
Example:
var configure validate.BoolBuilderFunc[bool] = func(rules *validate.BoolBuilder[bool]) {
rules.Required()
}
_ = configure
type BoolSchema ¶
type BoolSchema[B ~bool] struct { // contains filtered or unexported fields }
BoolSchema validates booleans and named bool types. Create one with Bool. Construction settings belong to BoolBuilder, not published schemas.
False counts as absent, so Required on a bool means "must be true". Prefer BoolBuilder.Accepted and BoolBuilder.Declined, or wrap the schema in Ptr so false is a present value.
Example:
schema := validate.Bool(func(value *validate.BoolBuilder[bool]) {
value.Accepted()
})
if err := schema.Validate(context.Background(), true); err != nil {
panic(err)
}
func Bool ¶
func Bool[B ~bool](configure ...BoolBuilderFunc[B]) BoolSchema[B]
Bool publishes a schema for B, inferred from typed callbacks. Callbacks run once in order and retained drafts cannot change the published result.
Example:
schema := validate.Bool(func(value *validate.BoolBuilder[bool]) {
value.Declined()
})
if err := schema.Validate(context.Background(), false); err != nil {
panic(err)
}
func (BoolSchema[B]) JSONSchema ¶
func (schema BoolSchema[B]) JSONSchema() ([]byte, error)
JSONSchema renders this schema's supported JSON Schema constraints. Runtime-only rules remain enforced by Parse and Validate; invalid schema definitions or values that JSON cannot encode return an error. As with StringSchema.JSONSchema, definition checks never execute validation callbacks; recorded construction errors wrap ErrInvalidSchema.
Example:
schema := validate.Bool[bool]()
document, err := schema.JSONSchema()
if err != nil {
panic(err)
}
_ = document
func (BoolSchema[B]) Parse ¶
func (rules BoolSchema[B]) Parse(ctx context.Context, v B) (B, error)
Parse checks the input and returns its normalized, defaulted result. It copies storage before applying schema changes and returns the zero value with Errors or a custom Check error when validation fails.
Example:
schema := validate.Bool[bool]()
value, err := schema.Parse(context.Background(), true)
if err != nil {
panic(err)
}
_ = value
func (BoolSchema[B]) Validate ¶
func (rules BoolSchema[B]) Validate(ctx context.Context, v B) error
Validate checks the input using the same preparation and rules as Parse, without returning the prepared value. It returns nil, Errors, or a custom Check error; caller-owned input is not modified.
Example:
schema := validate.Bool[bool]()
if err := schema.Validate(context.Background(), true); err != nil {
panic(err)
}
type Catalog ¶
type Catalog struct {
// Default is the locale consulted after the requested locale and its
// base language.
Default string
// Locales maps a language tag to its messages.
Locales map[string]Messages
}
Catalog holds message templates per locale.
Locales are keyed by language tag, such as "en" or "es-MX". Default names the locale used when the requested one has no message for a code.
type ChildBuilderFunc ¶
type ChildBuilderFunc[P any] = func(P)
ChildBuilderFunc edits one exact concrete child draft. Its alias identity permits ordinary typed functions and slices without adapters.
Example:
var name validate.ChildBuilderFunc[*validate.StringBuilder[string]] = func(rules *validate.StringBuilder[string]) {
rules.Required()
}
_ = name
type ConditionBuilder ¶
type ConditionBuilder struct {
// contains filtered or unexported fields
}
ConditionBuilder records read-only observations of the nearest enclosing struct. Multiple observations on one draft are ANDed. Paths use dotted Go field names through structs and pointer-to-struct fields, never JSON names, collection indexes or parent references. Nil intermediate pointers are absent. The draft performs no validation and never changes observed values.
Example:
type Form struct {
Mode, Name string
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Name", func(name *validate.StringBuilder[string]) {
name.RequiredIf(func(predicate *validate.ConditionBuilder) {
predicate.Eq("Mode", "active")
})
})
})
_ = schema
func (*ConditionBuilder) Absent ¶
func (predicate *ConditionBuilder) Absent(path string) *ConditionBuilder
Absent complements Present, including a path behind a nil intermediate pointer. It never allocates a pointer to make the path reachable.
Example:
var anonymous validate.ConditionBuilderFunc = func(predicate *validate.ConditionBuilder) {
predicate.Absent("Profile")
}
_ = anonymous
func (*ConditionBuilder) And ¶
func (predicate *ConditionBuilder) And(configure ...ConditionBuilderFunc) *ConditionBuilder
And adds one nonempty conjunctive group. Callbacks share one child draft; the published group is independent of later edits to that draft.
Example:
var active validate.ConditionBuilderFunc = func(predicate *validate.ConditionBuilder) {
predicate.And(func(group *validate.ConditionBuilder) {
group.Eq("Role", "admin").Present("Token")
})
}
_ = active
func (*ConditionBuilder) Contains ¶
func (predicate *ConditionBuilder) Contains[K comparable, V any](path string, match func(K, V) bool) *ConditionBuilder
Contains observes existence of a matching collection entry. Slices require K to be exact int; maps require exact K,V. It emits no validation errors.
Example:
var positive validate.ConditionBuilderFunc = func(predicate *validate.ConditionBuilder) {
predicate.Contains("Scores", func(index, value int) bool {
return value > 0
})
}
_ = positive
func (*ConditionBuilder) CountWhere ¶
func (predicate *ConditionBuilder) CountWhere[K comparable, V any](path string, match func(K, V) bool, configure ...IntBuilderFunc[int]) *ConditionBuilder
CountWhere observes pure numeric constraints on the matching entry count. Zero is checked as present, and invalid constraint settings fail construction.
Example:
var enough validate.ConditionBuilderFunc = func(predicate *validate.ConditionBuilder) {
predicate.CountWhere("Scores", func(index, value int) bool {
return value > 0
}, func(count *validate.IntBuilder[int]) {
count.Min(2)
})
}
_ = enough
func (*ConditionBuilder) Eq ¶
func (predicate *ConditionBuilder) Eq(path string, value any) *ConditionBuilder
Eq observes equality with value, using the field's exact type or a constant of the same scalar family. A missing nested field never compares equal.
Example:
var active validate.ConditionBuilderFunc = func(predicate *validate.ConditionBuilder) {
predicate.Eq("Profile.Role", "admin")
}
_ = active
func (*ConditionBuilder) Every ¶
func (predicate *ConditionBuilder) Every[K comparable, V any](path string, match func(K, V) bool) *ConditionBuilder
Every observes universal matching, including present empty collections. Nil collections use empty iteration; unreachable nested paths return false. Match must be pure and must not mutate observed values.
Example:
var positive validate.ConditionBuilderFunc = func(predicate *validate.ConditionBuilder) {
predicate.Every("Scores", func(index, value int) bool {
return value > 0
})
}
_ = positive
func (*ConditionBuilder) Has ¶
func (predicate *ConditionBuilder) Has[K comparable](path string, key K) *ConditionBuilder
Has observes exact map-key existence, even when the entry's value is zero. Its key type is inferred and checked when the enclosing schema is built.
Example:
var admin validate.ConditionBuilderFunc = func(predicate *validate.ConditionBuilder) {
predicate.Has("Scores", "admin")
}
_ = admin
func (*ConditionBuilder) HasAll ¶
func (predicate *ConditionBuilder) HasAll[K comparable](path string, keys ...K) *ConditionBuilder
HasAll observes whether every map key exists, independent of stored values. An empty list is true even for nil maps. Unreachable nested paths are false.
Example:
var complete validate.ConditionBuilderFunc = func(predicate *validate.ConditionBuilder) {
predicate.HasAll("Scores", "name", "age")
}
_ = complete
func (*ConditionBuilder) HasAny ¶
func (predicate *ConditionBuilder) HasAny[K comparable](path string, keys ...K) *ConditionBuilder
HasAny observes whether any listed map key exists. Empty lists return false; caller-owned key slices are copied before the observation is retained.
Example:
var staff validate.ConditionBuilderFunc = func(predicate *validate.ConditionBuilder) {
predicate.HasAny("Scores", "admin", "editor")
}
_ = staff
func (*ConditionBuilder) If ¶
func (predicate *ConditionBuilder) If[T any](fn func(T) bool) *ConditionBuilder
If observes a pure function of the exact nearest enclosing struct type T. The function must not mutate its argument or values reachable from it. A nil function or mismatched T is a construction error, not a false result.
Example:
type Form struct {
Enabled bool
}
var enabled validate.ConditionBuilderFunc = func(predicate *validate.ConditionBuilder) {
predicate.If(func(form Form) bool {
return form.Enabled
})
}
_ = enabled
func (*ConditionBuilder) In ¶
func (predicate *ConditionBuilder) In(path string, values ...any) *ConditionBuilder
In observes membership in a copied value list. Type mismatches are reported during enclosing schema construction; an unresolved nested path is false.
Example:
var staff validate.ConditionBuilderFunc = func(predicate *validate.ConditionBuilder) {
predicate.In("Role", "admin", "editor")
}
_ = staff
func (*ConditionBuilder) Not ¶
func (predicate *ConditionBuilder) Not(configure ...ConditionBuilderFunc) *ConditionBuilder
Not negates one nonempty AND group. This logical complement deliberately turns a false comparison on a missing nested path into true.
Example:
var nonadmin validate.ConditionBuilderFunc = func(predicate *validate.ConditionBuilder) {
predicate.Not(func(group *validate.ConditionBuilder) {
group.Eq("Profile.Role", "admin")
})
}
_ = nonadmin
func (*ConditionBuilder) NotEq ¶
func (predicate *ConditionBuilder) NotEq(path string, value any) *ConditionBuilder
NotEq observes inequality with value. Unlike Not(Eq), an unresolved nested path returns false. Direct scalar zero values remain ordinary comparisons.
Example:
var ordinary validate.ConditionBuilderFunc = func(predicate *validate.ConditionBuilder) {
predicate.NotEq("Profile.Role", "admin")
}
_ = ordinary
func (*ConditionBuilder) NotIn ¶
func (predicate *ConditionBuilder) NotIn(path string, values ...any) *ConditionBuilder
NotIn observes nonmembership in a copied value list. A missing intermediate pointer returns false rather than comparing a fabricated scalar zero.
Example:
var customer validate.ConditionBuilderFunc = func(predicate *validate.ConditionBuilder) {
predicate.NotIn("Role", "admin", "editor")
}
_ = customer
func (*ConditionBuilder) Or ¶
func (predicate *ConditionBuilder) Or(configure ...ConditionBuilderFunc) *ConditionBuilder
Or adds one nonempty disjunctive group. Observations within the group's shared draft are alternatives; other observations on the parent remain ANDed.
Example:
var staff validate.ConditionBuilderFunc = func(predicate *validate.ConditionBuilder) {
predicate.Or(func(group *validate.ConditionBuilder) {
group.Eq("Role", "admin").Eq("Role", "editor")
})
}
_ = staff
func (*ConditionBuilder) Present ¶
func (predicate *ConditionBuilder) Present(path string) *ConditionBuilder
Present observes nonzero scalars and nonnil pointers, slices and maps. An allocated pointer to zero and an allocated empty collection are present.
Example:
var tagged validate.ConditionBuilderFunc = func(predicate *validate.ConditionBuilder) {
predicate.Present("Tags")
}
_ = tagged
func (*ConditionBuilder) UniqueBy ¶
func (predicate *ConditionBuilder) UniqueBy[K comparable, V any, U comparable](path string, project func(K, V) U) *ConditionBuilder
UniqueBy observes projection uniqueness without emitting diagnostics. Exact key/value types are checked at construction and projections must be pure.
Example:
var distinct validate.ConditionBuilderFunc = func(predicate *validate.ConditionBuilder) {
predicate.UniqueBy("Scores", func(index, value int) int {
return value
})
}
_ = distinct
type ConditionBuilderFunc ¶
type ConditionBuilderFunc = func(*ConditionBuilder)
ConditionBuilderFunc edits one temporary observation draft. Callbacks run once in order. A nil callback panics; an empty resulting expression is an invalid schema, including an empty And, Or or Not group.
Example:
var active validate.ConditionBuilderFunc = func(predicate *validate.ConditionBuilder) {
predicate.Eq("Mode", "active")
}
_ = active
type Duration ¶
Duration is a time.Duration that encodes as Go duration text such as "182ms" or "1h30m" instead of a nanosecond count.
encoding/json/v2 refuses to marshal a bare time.Duration because it has no default representation. Declaring a field as Duration gives it one, through MarshalText and UnmarshalText, and the same text is what StringBuilder.Duration accepts. Describe such a field with Text: Duration reports the custom "go-duration" format to Text and Infer. The standard JSON Schema "duration" format instead describes the incompatible RFC 3339 Appendix A grammar, such as "PT1H30M".
Example:
type Result struct {
Elapsed validate.Duration `json:"elapsed"`
}
out, _ := json.Marshal(Result{
Elapsed: validate.Duration(182 * time.Millisecond),
})
// {"elapsed":"182ms"}
func (Duration) JSONSchemaFormat ¶
JSONSchemaFormat returns "go-duration", the custom annotation that Text and Infer render for Go duration text. It deliberately does not claim the standard RFC 3339 Appendix A "duration" format. Any type with a JSONSchemaFormat method gets the same annotation treatment.
Example:
duration := validate.Duration(time.Second) format := duration.JSONSchemaFormat() _ = format
func (Duration) MarshalText ¶
MarshalText implements encoding.TextMarshaler. It returns the text of time.Duration.String, such as "182ms". It never fails.
Example:
duration := validate.Duration(time.Second)
text, err := duration.MarshalText()
if err != nil {
panic(err)
}
_ = text
func (Duration) Std ¶
Std returns the value as a time.Duration.
Example:
duration := validate.Duration(time.Second) standard := duration.Std() _ = standard
func (*Duration) UnmarshalText ¶
UnmarshalText implements encoding.TextUnmarshaler. It parses text with time.ParseDuration, so "1.5h" and "-3s" are accepted, and returns that function's error for anything else. d is left unchanged on error.
Example:
duration := validate.Duration(time.Second)
if err := duration.UnmarshalText([]byte("250ms")); err != nil {
panic(err)
}
type EncodedSchema ¶
type EncodedSchema struct {
// contains filtered or unexported fields
}
EncodedSchema checks an already encoded JSON instance without changing it. Construct it with FromJSONSchemaStrict. The zero value is invalid. Published schemas own their compiled state and are safe for concurrent use; no caller bytes, application callbacks, normalizers, or mutable defaults are retained. Unlike JSONSchema, null is a value, missing properties remain missing, and default and format are annotations, never transformations or assertions.
This is a bounded, self-contained validator, not an unrestricted JSON Schema implementation. See FromJSONSchemaStrict for its vocabulary and dialects, and EncodedSchema.Validate for resource and error contracts.
Example:
check, err := validate.FromJSONSchemaStrict([]byte(`{"type":"integer"}`))
if err != nil {
return err
}
return check.Validate(context.Background(), []byte(`9007199254740993`))
func FromJSONSchemaStrict ¶
func FromJSONSchemaStrict(document []byte) (EncodedSchema, error)
FromJSONSchemaStrict compiles a self-contained draft-07 or 2020-12 schema for strict wire validation. Omitted or empty $schema selects 2020-12; identifiers are http(s)://json-schema.org/draft-07/schema# and https://json-schema.org/draft/2020-12/schema. Mixed embedded dialects fail. Draft-07 $ref ignores assertion siblings; 2020-12 evaluates them. Local $id, JSON Pointer refs, definitions/$defs, anchors, and dynamic references resolve only within the supplied document. External targets fail without any I/O. Pointers must name a compiled schema location (the root or a recognized schema-valued keyword), not a value embedded in an annotation.
Supported assertions are boolean schemas; type (including unions and null); enum/const; minimum/maximum/exclusiveMinimum/exclusiveMaximum/multipleOf; minLength/maxLength/pattern; minItems/maxItems/uniqueItems; items/prefixItems/ additionalItems (legacy tuple rules for draft-07); contains/minContains/ maxContains; minProperties/maxProperties/required/properties/patternProperties/ propertyNames/additionalProperties; dependencies (draft-07), dependentRequired/ dependentSchemas; allOf/anyOf/oneOf/not/if/then/else; and unevaluatedProperties/ unevaluatedItems with successful-branch annotation propagation. All numeric comparisons are exact. String lengths count Unicode code points. Patterns use Go's RE2 dialect, not the full ECMA-262 regex dialect. As in the dialect-specific array vocabularies, draft-07 ignores prefixItems, and additionalItems has no effect without draft-07 tuple items. Legacy dependencies is rejected outside draft-07 rather than silently skipped.
Annotation keywords are $comment/title/description/default/examples/format/ deprecated/readOnly/writeOnly/contentEncoding/contentMediaType/contentSchema. Defaults need not satisfy their schema and are never applied. contentSchema is compiled for well-formedness and references but never checks decoded content. x-* extensions are ignored annotations. Every other unknown keyword fails compilation, deliberately stricter than implementations that ignore unknown assertions. $vocabulary requires explicit 2020-12; unsupported required vocabularies, including format-assertion, fail compilation.
The returned value owns all retained state. Syntax, unsupported vocabulary, malformed keyword values, and unresolved references wrap ErrInvalidSchema without including schema text. Resource failures also retain ErrEncodedLimit. See EncodedSchema.Validate for fixed allocation/work bounds. Compilation never validates defaults or calls application code.
Example:
document := []byte(`{
"type":"object", "required":["n"],
"properties":{"n":{"type":"integer"}}
}`)
check, err := validate.FromJSONSchemaStrict(document)
if err != nil {
return err
}
return check.Validate(context.Background(), []byte(`{"n":1e1000}`))
Example ¶
ExampleFromJSONSchemaStrict demonstrates exact wire validation without an application value, normalization, defaults, or a binary64 conversion.
package main
import (
"context"
"fmt"
"arkoren.dev/foundation/validate"
)
func main() {
check, err := validate.FromJSONSchemaStrict([]byte(`{"type":"integer","minimum":9007199254740993}`))
if err != nil {
fmt.Println("compile:", err)
return
}
fmt.Println(check.Validate(context.Background(), []byte(`9007199254740993`)))
}
Output: <nil>
func (EncodedSchema) Validate ¶
func (schema EncodedSchema) Validate(ctx context.Context, document []byte) error
Validate checks exactly one UTF-8 JSON document. It preserves the supplied bytes, distinguishes null, absent keys, and zero, and compares numbers by exact decimal value, including numbers outside binary64's range.
A mismatch returns Errors (fail-fast, with a JSON Pointer and keyword code, without instance values or schema literals). Malformed JSON wraps ErrEncodedJSON. The zero schema wraps ErrInvalidSchema. Cancellation and deadlines retain context error identities. Resource refusals wrap ErrEncodedLimit, never Errors; callers must keep those classes distinct. Do not expose returned pointers to an untrusted client without redaction.
Each schema/instance is limited to 8 MiB and 256 container levels. Compilation allows 16,384 schema nodes. Decoding and evaluation each allow 1,000,000 work steps; evaluation allows 512 nested calls. Every numeric coefficient allows 4,096 digits and its explicit decimal exponent must be within [-4096,4096], including for zero. Limits are checked before big.Rat allocation; excess is refused, never rounded. Ordinary out-of-float64 numbers such as 1e1000 work. The sum of coefficient digits plus absolute exponents is limited to 64 Mi digits per decoded document. Structural keys for equality and uniqueness have a cumulative 64 MiB encoding budget per validation, including repeated comparisons and conservatively charged prefixes. These are data/work bounds, not an exact Go heap bound: slice capacity, copies, and runtime metadata also use memory. The limits prevent short exponent tokens multiplying storage. Schema URIs/references and traversed JSON Pointers are limited to 16 KiB; this prevents multiplicative storage growth from long nested names or IDs. The compiled URI index is limited to 32 MiB of keys, including aliases. Unproductive reference cycles are resource failures; recursive schemas that descend through the instance are supported. Cancellation is checked between tokens, child visits, branches, and references, not inside bounded standard library operations. A nil context is caller misuse, as with other Go APIs.
Example:
check, err := validate.FromJSONSchemaStrict([]byte(`{
"properties":{"count":{"type":"integer"}}
}`))
if err != nil {
return err
}
err = check.Validate(context.Background(), []byte(`{"count":null}`))
var failures validate.Errors
if errors.As(err, &failures) {
_ = failures // schema mismatch; redact paths at a protocol boundary
return errors.New("output does not match its schema")
}
return err // cancellation, resource refusal, malformed JSON, or nil
Example ¶
ExampleEncodedSchema_Validate demonstrates the adapter's classification boundary: only validate.Errors means that a valid JSON instance mismatches.
package main
import (
"context"
"errors"
"fmt"
"arkoren.dev/foundation/validate"
)
func main() {
check, err := validate.FromJSONSchemaStrict([]byte(`{"properties":{"count":{"type":"integer"}}}`))
if err != nil {
fmt.Println("compile:", err)
return
}
err = check.Validate(context.Background(), []byte(`{"count":null}`))
var failures validate.Errors
if errors.As(err, &failures) {
fmt.Println("mismatch:", failures["/count"][0].Code)
return
}
fmt.Println("operational error:", err)
}
Output: mismatch: type
type Errors ¶
Errors collects violations by RFC 6901 JSON Pointer. The pointer "" addresses the validated value itself and "/items/0/qty" the qty field of the first item.
Errors implements error. Validate and Parse return a nil error, never an empty Errors.
Example ¶
ExampleErrors shows the JSON form that API clients receive.
package main
import (
"context"
"encoding/json/v2"
"fmt"
"arkoren.dev/foundation/validate"
)
func main() {
err := validate.String(func(value *validate.StringBuilder[string]) {
value.Min(3)
}).Validate(context.Background(), "ab")
encoded, err := json.Marshal(err)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(encoded))
}
Output: {"":[{"code":"string.min","params":{"min":3},"message":"must be at least 3 characters"}]}
func (Errors) Add ¶
Add appends violation at pointer. The receiver must not be nil.
Example:
violations := validate.Errors{}
violations.Add("/email", validate.Violation{
Code: "required",
})
_ = violations["/email"]
func (Errors) All ¶
All yields every pointer with its violations in a stable order. Pointers are compared segment by segment, and segments made of digits compare numerically, so "/items/2" precedes "/items/10".
Example:
violations := validate.Errors{}
violations.Add("/email", validate.Violation{
Code: "required",
})
for pointer, failures := range violations.All() {
_, _ = pointer, failures
}
func (Errors) Error ¶
Error summarizes the violations in English, in the order of Errors.All.
Example:
violations := validate.Errors{}
violations.Add("/email", validate.Violation{
Code: "required",
})
summary := violations.Error()
_ = summary
func (Errors) Localize ¶
Localize returns a copy whose messages are rendered again using the catalog and locale of ctx. Violations whose code no catalog knows keep their message. Each copied violation owns independent parameter containers within Fail's copying limits, even when its message is unchanged. Arbitrary objects in parameters remain shared; Localize does not make them safe for concurrent mutation. The receiver is not modified.
Example:
violations := validate.Errors{}
violations.Add("/email", validate.Violation{
Code: "string.min", Params: map[string]any{"min": 3},
})
localized := violations.Localize(context.Background())
localized["/email"][0].Params["min"] = 5
fmt.Println(violations["/email"][0].Params["min"]) // 3
type FileBuilder ¶
type FileBuilder struct {
// contains filtered or unexported fields
}
FileBuilder configures a detached FileSchema during construction. Settings return the same draft. Retaining a draft cannot change a schema; concurrent mutation of a draft is not supported.
Example:
var configure validate.FileBuilderFunc = func(rules *validate.FileBuilder) {
rules.Required()
}
_ = configure
func (*FileBuilder) Bail ¶
func (draft *FileBuilder) Bail() *FileBuilder
Bail stops checking this value at its first failure. By default every failure is reported.
Example:
type Value struct {
Name string
}
type Form struct {
Value *multipart.FileHeader
Peer *multipart.FileHeader
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FileBuilder) {
rules.Bail()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FileBuilder) Check ¶
func (draft *FileBuilder) Check(fn func(context.Context, *multipart.FileHeader) error) *FileBuilder
Check adds a custom rule that runs only for present values. Return Fail (or At in a Struct check) to report a violation; any other error aborts validation and is returned to the caller unchanged.
Example:
type Value struct {
Name string
}
type Form struct {
Value *multipart.FileHeader
Peer *multipart.FileHeader
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FileBuilder) {
rules.Check(func(_ context.Context, value *multipart.FileHeader) error {
return nil
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FileBuilder) Describe ¶
func (draft *FileBuilder) Describe(text string) *FileBuilder
Describe sets the human-readable description that JSONSchema renders as "description". It does not affect validation. Use it for field and tool descriptions.
Example:
type Value struct {
Name string
}
type Form struct {
Value *multipart.FileHeader
Peer *multipart.FileHeader
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FileBuilder) {
rules.Describe("A display value")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FileBuilder) EqField ¶
func (draft *FileBuilder) EqField(field string) *FileBuilder
EqField requires the value to equal the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value *multipart.FileHeader
Peer *multipart.FileHeader
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FileBuilder) {
rules.EqField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FileBuilder) ExcludeIf ¶
func (draft *FileBuilder) ExcludeIf(configure ...ConditionBuilderFunc) *FileBuilder
ExcludeIf treats the value as absent, and clears it, when the conditions hold. Later ordinary value constraints skip absence, but later presence constraints still observe it and can report violations. Unconditional preparation may already have run before this rule is evaluated.
Example:
type Value struct {
Name string
}
type Form struct {
Value *multipart.FileHeader
Peer *multipart.FileHeader
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FileBuilder) {
rules.ExcludeIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FileBuilder) Extensions ¶
func (rules *FileBuilder) Extensions(exts ...string) *FileBuilder
Extensions requires the client filename to end in one of exts. The comparison ignores case and a leading dot, so "PNG" and ".png" both match "photo.PNG". The extension is only what the client claimed; pair it with FileBuilder.Types to check the content.
Example:
schema := validate.File(func(upload *validate.FileBuilder) {
upload.Extensions("png", "jpg")
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FileBuilder) Max ¶
func (rules *FileBuilder) Max(n int64) *FileBuilder
Max allows a file of at most n bytes.
Example:
schema := validate.File(func(upload *validate.FileBuilder) {
upload.Max(2 << 20)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FileBuilder) Min ¶
func (rules *FileBuilder) Min(n int64) *FileBuilder
Min requires a file of at least n bytes.
Example:
schema := validate.File(func(upload *validate.FileBuilder) {
upload.Min(1)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FileBuilder) NeField ¶
func (draft *FileBuilder) NeField(field string) *FileBuilder
NeField requires the value to differ from the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value *multipart.FileHeader
Peer *multipart.FileHeader
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FileBuilder) {
rules.NeField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FileBuilder) Normalize ¶
func (draft *FileBuilder) Normalize(fn func(*multipart.FileHeader) *multipart.FileHeader) *FileBuilder
Normalize adds a custom normalizer. It runs before the presence check, Default and every rule, in the order written among the normalizers. It must return the value it is given or a new one, and must not modify its argument. Normalize cannot be used on Map key schemas.
Example:
type Value struct {
Name string
}
type Form struct {
Value *multipart.FileHeader
Peer *multipart.FileHeader
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FileBuilder) {
rules.Normalize(func(value *multipart.FileHeader) *multipart.FileHeader {
return value
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FileBuilder) ProhibitedIf ¶
func (draft *FileBuilder) ProhibitedIf(configure ...ConditionBuilderFunc) *FileBuilder
ProhibitedIf fails when the value is present and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value *multipart.FileHeader
Peer *multipart.FileHeader
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FileBuilder) {
rules.ProhibitedIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FileBuilder) ProhibitedUnless ¶
func (draft *FileBuilder) ProhibitedUnless(configure ...ConditionBuilderFunc) *FileBuilder
ProhibitedUnless fails when the value is present and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value *multipart.FileHeader
Peer *multipart.FileHeader
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FileBuilder) {
rules.ProhibitedUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FileBuilder) Required ¶
func (draft *FileBuilder) Required() *FileBuilder
Required fails when the value is absent. Absent means zero, or nil for pointers, slices and maps. It cannot be combined with Default.
Example:
type Value struct {
Name string
}
type Form struct {
Value *multipart.FileHeader
Peer *multipart.FileHeader
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FileBuilder) {
rules.Required()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FileBuilder) RequiredIf ¶
func (draft *FileBuilder) RequiredIf(configure ...ConditionBuilderFunc) *FileBuilder
RequiredIf fails when the value is absent and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value *multipart.FileHeader
Peer *multipart.FileHeader
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FileBuilder) {
rules.RequiredIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FileBuilder) RequiredUnless ¶
func (draft *FileBuilder) RequiredUnless(configure ...ConditionBuilderFunc) *FileBuilder
RequiredUnless fails when the value is absent and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value *multipart.FileHeader
Peer *multipart.FileHeader
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FileBuilder) {
rules.RequiredUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FileBuilder) RequiredWith ¶
func (draft *FileBuilder) RequiredWith(fields ...string) *FileBuilder
RequiredWith fails when the value is absent and any of the sibling fields is present.
Example:
type Value struct {
Name string
}
type Form struct {
Value *multipart.FileHeader
Peer *multipart.FileHeader
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FileBuilder) {
rules.RequiredWith("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FileBuilder) RequiredWithAll ¶
func (draft *FileBuilder) RequiredWithAll(fields ...string) *FileBuilder
RequiredWithAll fails when the value is absent and all of the sibling fields are present.
Example:
type Value struct {
Name string
}
type Form struct {
Value *multipart.FileHeader
Peer *multipart.FileHeader
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FileBuilder) {
rules.RequiredWithAll("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FileBuilder) RequiredWithout ¶
func (draft *FileBuilder) RequiredWithout(fields ...string) *FileBuilder
RequiredWithout fails when the value is absent and any of the sibling fields is absent.
Example:
type Value struct {
Name string
}
type Form struct {
Value *multipart.FileHeader
Peer *multipart.FileHeader
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FileBuilder) {
rules.RequiredWithout("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FileBuilder) Types ¶
func (rules *FileBuilder) Types(types ...string) *FileBuilder
Types requires the detected content type to be one of types. The type is detected from the first 512 bytes of the file with http.DetectContentType, so the file is opened; a failure to open or read it is returned to the caller as an error rather than reported as a violation. Entries may be exact ("application/pdf") or wildcards ("image/*"), and parameters such as "; charset=utf-8" are ignored on both sides, so Types("text/plain") accepts "text/plain; charset=utf-8".
Example:
schema := validate.File(func(upload *validate.FileBuilder) {
upload.Types("image/png", "image/jpeg")
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FileBuilder) Use ¶
func (draft *FileBuilder) Use(schema Schema[*multipart.FileHeader]) *FileBuilder
Use adds rules from the same published schema role, as a value or nonnil pointer, before subsequent local settings. InferSchema contributes type-only documentation, not validation or missing child definitions. FromJSONSchema provides a separate decoded-JSON API, not a Schema value accepted here. Other schema roles are rejected even when their value type matches, because importing only their base could lose child rules. Schema-level rules accumulate. Overlapping child definitions are construction errors, and later local child callbacks cannot replace an imported child. Ptr permits an unconstrained scalar adapter to yield to a shared pointee. The source remains immutable. Typed nil pointers wrap ErrInvalidSchema.
Example:
var configure validate.FileBuilderFunc = func(rules *validate.FileBuilder) {
rules.Use(validate.File())
}
_ = configure
func (*FileBuilder) When ¶
func (draft *FileBuilder) When(condition ConditionBuilderFunc, configure ...func(*FileBuilder)) *FileBuilder
When applies additional rules when the condition holds for the enclosing struct. The extra schema runs in place, in the order written, and sees defaults and exclusions like the rest of the chain.
Example:
type Value struct {
Name string
}
type Form struct {
Value *multipart.FileHeader
Peer *multipart.FileHeader
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FileBuilder) {
rules.When(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
}, func(selected *validate.FileBuilder) {
selected.Required()
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
type FileBuilderFunc ¶
type FileBuilderFunc = func(*FileBuilder)
FileBuilderFunc edits one temporary FileBuilder. Constructors invoke callbacks once, synchronously in order; a nil supplied callback panics.
Example:
var configure validate.FileBuilderFunc = func(rules *validate.FileBuilder) {
rules.Required()
}
_ = configure
type FileSchema ¶
type FileSchema struct {
// contains filtered or unexported fields
}
FileSchema validates uploaded files as *multipart.FileHeader. Create one with File. A nil header is absent, so only FileBuilder.Required makes a missing upload an error.
The rules judge what the client sent: the size is the one the multipart parser counted, the extension is the client's filename extension, and the content type is detected from the file's first 512 bytes with http.DetectContentType, never from the client's Content-Type header. Detection is coarse. Office documents (.docx, .xlsx) detect as application/zip, so combine FileBuilder.Types("application/zip") with FileBuilder.Extensions("docx"). SVG detects as text/xml or text/plain and is deliberately not treated as an image, because it can carry scripts. There is no Image shorthand for the same reason.
A FileSchema works standalone and on Struct fields of type *multipart.FileHeader.
Example:
schema := validate.File(func(upload *validate.FileBuilder) {
upload.Max(2<<20).Extensions("png", "jpg")
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func File ¶
func File(configure ...FileBuilderFunc) FileSchema
File publishes a schema for *multipart.FileHeader. Callbacks run once in order; retained drafts cannot change published rules or allowed-type lists.
Example:
avatar := validate.File(func(upload *validate.FileBuilder) {
upload.Required().Max(2<<20).Extensions("png", "jpg").Types("image/png", "image/jpeg")
})
if _, err := avatar.JSONSchema(); err != nil {
panic(err)
}
func (FileSchema) JSONSchema ¶
func (schema FileSchema) JSONSchema() ([]byte, error)
JSONSchema renders this schema's supported JSON Schema constraints. Runtime-only rules remain enforced by Parse and Validate; invalid schema definitions or values that JSON cannot encode return an error. As with StringSchema.JSONSchema, definition checks never execute validation callbacks; recorded construction errors wrap ErrInvalidSchema.
Example:
schema := validate.File()
document, err := schema.JSONSchema()
if err != nil {
panic(err)
}
_ = document
func (FileSchema) Parse ¶
func (schema FileSchema) Parse(ctx context.Context, v *multipart.FileHeader) (*multipart.FileHeader, error)
Parse checks the input and returns its normalized, defaulted result. It copies storage before applying schema changes and returns the zero value with Errors or a custom Check error when validation fails.
Example:
schema := validate.File()
value, err := schema.Parse(context.Background(), nil)
if err != nil {
panic(err)
}
_ = value
func (FileSchema) Validate ¶
func (schema FileSchema) Validate(ctx context.Context, v *multipart.FileHeader) error
Validate checks the input using the same preparation and rules as Parse, without returning the prepared value. It returns nil, Errors, or a custom Check error; caller-owned input is not modified.
Example:
schema := validate.File()
if err := schema.Validate(context.Background(), nil); err != nil {
panic(err)
}
type FloatBuilder ¶
type FloatBuilder[N floating] struct {
// contains filtered or unexported fields
}
FloatBuilder configures a detached FloatSchema during construction. Settings return the same draft. Retaining a draft cannot change a schema; concurrent mutation of a draft is not supported.
Example:
var configure validate.FloatBuilderFunc[float64] = func(rules *validate.FloatBuilder[float64]) {
rules.Required()
}
_ = configure
func (*FloatBuilder[N]) Abs ¶
func (number *FloatBuilder[N]) Abs() *FloatBuilder[N]
Abs replaces the value with its absolute value. It is a normalizer: it runs before presence, Default and every rule, in the order written.
Example:
schema := validate.Float(func(number *validate.FloatBuilder[float64]) {
number.Abs()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FloatBuilder[N]) Bail ¶
func (draft *FloatBuilder[N]) Bail() *FloatBuilder[N]
Bail stops checking this value at its first failure. By default every failure is reported.
Example:
type Value struct {
Name string
}
type Form struct {
Value float64
Peer float64
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FloatBuilder[float64]) {
rules.Bail()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FloatBuilder[N]) Between ¶
func (number *FloatBuilder[N]) Between(low, high N) *FloatBuilder[N]
Between requires a value from low to high, inclusive. Both bounds must be finite; FloatSchema documents how non-finite bounds are recorded and reported. A reversed range retains its immediate ErrInvalidSchema panic.
Example:
schema := validate.Float(func(number *validate.FloatBuilder[float64]) {
number.Between(0.5, 100)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FloatBuilder[N]) Check ¶
func (draft *FloatBuilder[N]) Check(fn func(context.Context, N) error) *FloatBuilder[N]
Check adds a custom rule that runs only for present values. Return Fail (or At in a Struct check) to report a violation; any other error aborts validation and is returned to the caller unchanged.
Example:
type Value struct {
Name string
}
type Form struct {
Value float64
Peer float64
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FloatBuilder[float64]) {
rules.Check(func(_ context.Context, value float64) error {
return nil
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FloatBuilder[N]) Clamp ¶
func (number *FloatBuilder[N]) Clamp(low, high N) *FloatBuilder[N]
Clamp limits the value to the range from low to high. It panics with ErrInvalidSchema when low is greater than high. It is a normalizer: it runs before presence, Default and every rule, in the order written.
Example:
schema := validate.Float(func(number *validate.FloatBuilder[float64]) {
number.Clamp(0, 100)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FloatBuilder[N]) Default ¶
func (draft *FloatBuilder[N]) Default(value N) *FloatBuilder[N]
Default sets the value Parse uses when the prepared input is absent. Registered defaults are checked while a Struct is built; standalone defaults are checked by execution, not metadata export. Input normalizers run before default selection and do not run again on the selected default. Arbitrary default objects retain application ownership. Default cannot be combined with Required.
Example:
type Value struct {
Name string
}
type Form struct {
Value float64
Peer float64
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FloatBuilder[float64]) {
rules.Default(3.5)
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FloatBuilder[N]) Describe ¶
func (draft *FloatBuilder[N]) Describe(text string) *FloatBuilder[N]
Describe sets the human-readable description that JSONSchema renders as "description". It does not affect validation. Use it for field and tool descriptions.
Example:
type Value struct {
Name string
}
type Form struct {
Value float64
Peer float64
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FloatBuilder[float64]) {
rules.Describe("A display value")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FloatBuilder[N]) EqField ¶
func (draft *FloatBuilder[N]) EqField(field string) *FloatBuilder[N]
EqField requires the value to equal the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value float64
Peer float64
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FloatBuilder[float64]) {
rules.EqField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FloatBuilder[N]) ExcludeIf ¶
func (draft *FloatBuilder[N]) ExcludeIf(configure ...ConditionBuilderFunc) *FloatBuilder[N]
ExcludeIf treats the value as absent, and clears it, when the conditions hold. Later ordinary value constraints skip absence, but later presence constraints still observe it and can report violations. Unconditional preparation may already have run before this rule is evaluated.
Example:
type Value struct {
Name string
}
type Form struct {
Value float64
Peer float64
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FloatBuilder[float64]) {
rules.ExcludeIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FloatBuilder[N]) Gt ¶
func (number *FloatBuilder[N]) Gt(limit N) *FloatBuilder[N]
Gt requires a value greater than limit. The bound must be finite; FloatSchema documents how invalid bounds are recorded and reported.
Example:
schema := validate.Float(func(number *validate.FloatBuilder[float64]) {
number.Gt(1)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FloatBuilder[N]) GtField ¶
func (number *FloatBuilder[N]) GtField(field string) *FloatBuilder[N]
GtField requires a value greater than the sibling field of the same type.
Example:
type Bounds struct {
Low, High float64
}
schema := validate.Struct(func(object *validate.StructBuilder[Bounds]) {
object.Field("High", func(number *validate.FloatBuilder[float64]) {
number.GtField("Low")
})
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FloatBuilder[N]) Gte ¶
func (number *FloatBuilder[N]) Gte(limit N) *FloatBuilder[N]
Gte requires a value greater than or equal to limit. The bound must be finite; FloatSchema documents how invalid bounds are recorded and reported.
Example:
schema := validate.Float(func(number *validate.FloatBuilder[float64]) {
number.Gte(1)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FloatBuilder[N]) GteField ¶
func (number *FloatBuilder[N]) GteField(field string) *FloatBuilder[N]
GteField requires a value greater than or equal to the sibling field.
Example:
type Bounds struct {
Low, High float64
}
schema := validate.Struct(func(object *validate.StructBuilder[Bounds]) {
object.Field("High", func(number *validate.FloatBuilder[float64]) {
number.GteField("Low")
})
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FloatBuilder[N]) Lt ¶
func (number *FloatBuilder[N]) Lt(limit N) *FloatBuilder[N]
Lt requires a value less than limit. The bound must be finite; FloatSchema documents how invalid bounds are recorded and reported.
Example:
schema := validate.Float(func(number *validate.FloatBuilder[float64]) {
number.Lt(100)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FloatBuilder[N]) LtField ¶
func (number *FloatBuilder[N]) LtField(field string) *FloatBuilder[N]
LtField requires a value less than the sibling field.
Example:
type Bounds struct {
Low, High float64
}
schema := validate.Struct(func(object *validate.StructBuilder[Bounds]) {
object.Field("Low", func(number *validate.FloatBuilder[float64]) {
number.LtField("High")
})
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FloatBuilder[N]) Lte ¶
func (number *FloatBuilder[N]) Lte(limit N) *FloatBuilder[N]
Lte requires a value less than or equal to limit. The bound must be finite; FloatSchema documents how invalid bounds are recorded and reported.
Example:
schema := validate.Float(func(number *validate.FloatBuilder[float64]) {
number.Lte(100)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FloatBuilder[N]) LteField ¶
func (number *FloatBuilder[N]) LteField(field string) *FloatBuilder[N]
LteField requires a value less than or equal to the sibling field.
Example:
type Bounds struct {
Low, High float64
}
schema := validate.Struct(func(object *validate.StructBuilder[Bounds]) {
object.Field("Low", func(number *validate.FloatBuilder[float64]) {
number.LteField("High")
})
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FloatBuilder[N]) Max ¶
func (number *FloatBuilder[N]) Max(limit N) *FloatBuilder[N]
Max allows at most limit. The bound must be finite; FloatSchema documents how invalid bounds are recorded and reported without stopping callbacks.
Example:
schema := validate.Float(func(number *validate.FloatBuilder[float64]) {
number.Max(100)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FloatBuilder[N]) Min ¶
func (number *FloatBuilder[N]) Min(limit N) *FloatBuilder[N]
Min requires at least limit. The bound must be finite; FloatSchema documents how invalid bounds are recorded and reported without stopping callbacks.
Example:
schema := validate.Float(func(number *validate.FloatBuilder[float64]) {
number.Min(0.5)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FloatBuilder[N]) MultipleOf ¶
func (number *FloatBuilder[N]) MultipleOf(factor N) *FloatBuilder[N]
MultipleOf requires a multiple of a finite, strictly positive factor; validated values may be negative. Zero retains its immediate ErrInvalidSchema panic. Negative and non-finite factors record sticky construction diagnostics: Struct aggregates them, standalone execution panics with ErrInvalidSchema, and JSONSchema returns an error wrapping that sentinel. Callbacks still finish. The check divides the shortest decimal JSON encodings of value and factor exactly and requires an integer quotient, as JSON Schema does. No epsilon is applied: a nearby decimal nonmultiple is rejected. Float32 retains its own encoding precision rather than being widened before decimal interpretation.
Example:
schema := validate.Float(func(number *validate.FloatBuilder[float64]) {
number.MultipleOf(0.5)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FloatBuilder[N]) NeField ¶
func (draft *FloatBuilder[N]) NeField(field string) *FloatBuilder[N]
NeField requires the value to differ from the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value float64
Peer float64
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FloatBuilder[float64]) {
rules.NeField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FloatBuilder[N]) NonNegative ¶
func (number *FloatBuilder[N]) NonNegative() *FloatBuilder[N]
NonNegative requires a value of zero or more.
Example:
schema := validate.Float(func(number *validate.FloatBuilder[float64]) {
number.NonNegative()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FloatBuilder[N]) Normalize ¶
func (draft *FloatBuilder[N]) Normalize(fn func(N) N) *FloatBuilder[N]
Normalize adds a custom normalizer. It runs before the presence check, Default and every rule, in the order written among the normalizers. It must return the value it is given or a new one, and must not modify its argument. Normalize cannot be used on Map key schemas.
Example:
type Value struct {
Name string
}
type Form struct {
Value float64
Peer float64
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FloatBuilder[float64]) {
rules.Normalize(func(value float64) float64 {
return value
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FloatBuilder[N]) NotOneOf ¶
func (number *FloatBuilder[N]) NotOneOf(values ...N) *FloatBuilder[N]
NotOneOf rejects the listed values.
Example:
schema := validate.Float(func(number *validate.FloatBuilder[float64]) {
number.NotOneOf(13)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FloatBuilder[N]) OneOf ¶
func (number *FloatBuilder[N]) OneOf(values ...N) *FloatBuilder[N]
OneOf accepts only the listed values.
Example:
schema := validate.Float(func(number *validate.FloatBuilder[float64]) {
number.OneOf(1, 2.5)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FloatBuilder[N]) Positive ¶
func (number *FloatBuilder[N]) Positive() *FloatBuilder[N]
Positive requires a value greater than zero.
Example:
schema := validate.Float(func(number *validate.FloatBuilder[float64]) {
number.Positive()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FloatBuilder[N]) ProhibitedIf ¶
func (draft *FloatBuilder[N]) ProhibitedIf(configure ...ConditionBuilderFunc) *FloatBuilder[N]
ProhibitedIf fails when the value is present and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value float64
Peer float64
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FloatBuilder[float64]) {
rules.ProhibitedIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FloatBuilder[N]) ProhibitedUnless ¶
func (draft *FloatBuilder[N]) ProhibitedUnless(configure ...ConditionBuilderFunc) *FloatBuilder[N]
ProhibitedUnless fails when the value is present and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value float64
Peer float64
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FloatBuilder[float64]) {
rules.ProhibitedUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FloatBuilder[N]) Required ¶
func (draft *FloatBuilder[N]) Required() *FloatBuilder[N]
Required fails when the value is absent. Absent means zero, or nil for pointers, slices and maps. It cannot be combined with Default.
Example:
type Value struct {
Name string
}
type Form struct {
Value float64
Peer float64
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FloatBuilder[float64]) {
rules.Required()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FloatBuilder[N]) RequiredIf ¶
func (draft *FloatBuilder[N]) RequiredIf(configure ...ConditionBuilderFunc) *FloatBuilder[N]
RequiredIf fails when the value is absent and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value float64
Peer float64
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FloatBuilder[float64]) {
rules.RequiredIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FloatBuilder[N]) RequiredUnless ¶
func (draft *FloatBuilder[N]) RequiredUnless(configure ...ConditionBuilderFunc) *FloatBuilder[N]
RequiredUnless fails when the value is absent and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value float64
Peer float64
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FloatBuilder[float64]) {
rules.RequiredUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FloatBuilder[N]) RequiredWith ¶
func (draft *FloatBuilder[N]) RequiredWith(fields ...string) *FloatBuilder[N]
RequiredWith fails when the value is absent and any of the sibling fields is present.
Example:
type Value struct {
Name string
}
type Form struct {
Value float64
Peer float64
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FloatBuilder[float64]) {
rules.RequiredWith("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FloatBuilder[N]) RequiredWithAll ¶
func (draft *FloatBuilder[N]) RequiredWithAll(fields ...string) *FloatBuilder[N]
RequiredWithAll fails when the value is absent and all of the sibling fields are present.
Example:
type Value struct {
Name string
}
type Form struct {
Value float64
Peer float64
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FloatBuilder[float64]) {
rules.RequiredWithAll("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FloatBuilder[N]) RequiredWithout ¶
func (draft *FloatBuilder[N]) RequiredWithout(fields ...string) *FloatBuilder[N]
RequiredWithout fails when the value is absent and any of the sibling fields is absent.
Example:
type Value struct {
Name string
}
type Form struct {
Value float64
Peer float64
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FloatBuilder[float64]) {
rules.RequiredWithout("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*FloatBuilder[N]) Round ¶
func (number *FloatBuilder[N]) Round(places int) *FloatBuilder[N]
Round rounds the value to the given number of decimal places, halves away from zero. It panics with ErrInvalidSchema when places is negative. NaN, infinities and values too large to scale are unchanged. It is a normalizer, see Abs.
Example:
schema := validate.Float(func(number *validate.FloatBuilder[float64]) {
number.Round(2)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*FloatBuilder[N]) Use ¶
func (draft *FloatBuilder[N]) Use(schema Schema[N]) *FloatBuilder[N]
Use adds rules from the same published schema role, as a value or nonnil pointer, before subsequent local settings. InferSchema contributes type-only documentation, not validation or missing child definitions. FromJSONSchema provides a separate decoded-JSON API, not a Schema value accepted here. Other schema roles are rejected even when their value type matches, because importing only their base could lose child rules. Schema-level rules accumulate. Overlapping child definitions are construction errors, and later local child callbacks cannot replace an imported child. Ptr permits an unconstrained scalar adapter to yield to a shared pointee. The source remains immutable. Typed nil pointers wrap ErrInvalidSchema.
Example:
var configure validate.FloatBuilderFunc[float64] = func(rules *validate.FloatBuilder[float64]) {
rules.Use(validate.Float[float64]())
}
_ = configure
func (*FloatBuilder[N]) When ¶
func (draft *FloatBuilder[N]) When(condition ConditionBuilderFunc, configure ...func(*FloatBuilder[N])) *FloatBuilder[N]
When applies additional rules when the condition holds for the enclosing struct. The extra schema runs in place, in the order written, and sees defaults and exclusions like the rest of the chain.
Example:
type Value struct {
Name string
}
type Form struct {
Value float64
Peer float64
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.FloatBuilder[float64]) {
rules.When(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
}, func(selected *validate.FloatBuilder[float64]) {
selected.Required()
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
type FloatBuilderFunc ¶
type FloatBuilderFunc[N floating] = func(*FloatBuilder[N])
FloatBuilderFunc edits one temporary FloatBuilder. Constructors invoke callbacks once, synchronously in order; a nil supplied callback panics.
Example:
var configure validate.FloatBuilderFunc[float64] = func(rules *validate.FloatBuilder[float64]) {
rules.Required()
}
_ = configure
type FloatSchema ¶
type FloatSchema[N floating] struct {
// contains filtered or unexported fields
}
FloatSchema validates floating point numbers, including named types. Construct it with Float and configure its FloatBuilder; the published value is immutable.
WARNING: zero counts as absent and skips every rule except Required, so an optional schema configured with Min(1) accepts 0. Use Required or Ptr when zero is a meaningful value that must be range-checked. NaN input fails every range rule. Numeric bounds and MultipleOf factors must be finite. Non-finite arguments record sticky construction diagnostics; Struct aggregates them, standalone execution panics with ErrInvalidSchema, and JSONSchema returns an error wrapping that sentinel, even after a later finite setting. Exported bounds retain N's JSON encoding precision: a float32 bound of 0.1 is emitted as 0.1, not as the widened binary64 decimal. Runtime comparisons and existing numeric diagnostic parameter types are unchanged.
Example:
schema := validate.Float(func(number *validate.FloatBuilder[float64]) {
number.Min(0)
})
if err := schema.Validate(context.Background(), 1.5); err != nil {
panic(err)
}
func Float ¶
func Float[N floating](configure ...FloatBuilderFunc[N]) FloatSchema[N]
Float publishes a schema for floating N, inferred from typed callbacks. Callbacks run once in order; retained drafts cannot change published rules.
Example:
schema := validate.Float(func(number *validate.FloatBuilder[float32]) {
number.Max(10)
})
if err := schema.Validate(context.Background(), 1.5); err != nil {
panic(err)
}
func (FloatSchema[N]) JSONSchema ¶
func (schema FloatSchema[N]) JSONSchema() ([]byte, error)
JSONSchema renders this schema's supported JSON Schema constraints. Runtime-only rules remain enforced by Parse and Validate; invalid schema definitions or values that JSON cannot encode return an error. As with StringSchema.JSONSchema, definition checks never execute validation callbacks; non-finite bounds and other definition errors wrap ErrInvalidSchema.
Example:
schema := validate.Float[float64]()
document, err := schema.JSONSchema()
if err != nil {
panic(err)
}
_ = document
func (FloatSchema[N]) Parse ¶
func (schema FloatSchema[N]) Parse(ctx context.Context, v N) (N, error)
Parse checks the input and returns its normalized, defaulted result. It copies storage before applying schema changes and returns the zero value with Errors or a custom Check error when validation fails.
Example:
schema := validate.Float[float64]()
value, err := schema.Parse(context.Background(), 3.5)
if err != nil {
panic(err)
}
_ = value
func (FloatSchema[N]) Validate ¶
func (schema FloatSchema[N]) Validate(ctx context.Context, v N) error
Validate checks the input using the same preparation and rules as Parse, without returning the prepared value. It returns nil, Errors, or a custom Check error; caller-owned input is not modified.
Example:
schema := validate.Float[float64]()
if err := schema.Validate(context.Background(), 3.5); err != nil {
panic(err)
}
type InferSchema ¶
type InferSchema[T any] struct { // contains filtered or unexported fields }
InferSchema describes the JSON shape of the Go type T. Create one with Infer. A valid definition has no runtime rules: Validate and Parse accept values of T unchanged unless the context is canceled. Inference errors are still returned. This describes metadata, not encoded-instance validation; an encoder may reject a particular value, such as a nonfinite float, even when its Go type can be inferred.
Example:
schema := validate.Infer[struct{ Name string }]()
document, err := schema.JSONSchema()
if err != nil {
panic(err)
}
fmt.Println(string(document))
func Infer ¶
func Infer[T any]() InferSchema[T]
Infer builds a type-only schema for T by reflection, so output types can be published as JSON Schema without writing a shape. The mapping follows what encoding/json/v2 produces:
- string, integer, unsigned, float and bool kinds, and named types of them, become string, integer, integer with minimum 0, number and boolean.
- A type whose value or pointer implements encoding.TextMarshaler becomes a string, with "format" from its JSONSchemaFormat() string method if it has one, so Duration is {"type":"string","format":"go-duration"}. This is checked before the kind, because Duration's kind is int64. time.Time is the exception: it is {"type":"string","format":"date-time"}, as Time renders it.
- []byte and [N]byte are strings (base64 in JSON). Sequences of a defined uint8 element type are arrays, following JSON-v2 dispatch.
- A struct becomes an object over its JSON fields, named, promoted and excluded exactly like Struct names them. A field is listed in "required" unless its json tag has omitempty or omitzero, or its owner is an embedded pointer that can be nil. Explicit embed, inline and unknown options are not modeled and their fields are omitted. Numeric fields tagged with string become strings. Fields with a format option become {} because formatter-specific representations are not modeled. This does not guarantee that the encoder accepts the option.
- Slices and arrays become arrays, maps become objects whose "additionalProperties" is the value schema, and a pointer is its pointee (Ptr does the same, nil is not modeled). Map keys may be strings, integers, floats, custom JSON/text marshalers, interfaces or pointers to supported key types. The encoder still checks actual key values and can reject nil pointers or a nonstring custom representation.
- any and other interfaces become {}, like Any. So do types with a MarshalJSON method, whose JSON shape cannot be known, unless they explicitly implement JSONTypeProvider for a native slice or map shape.
"required" only describes the output: the key is always present. Infer does not enforce it, because false, 0 and "" are absent in this package and would reject real outputs such as count: 0.
A recursive type, such as a tree node with a Children []Node field, is described down to its second occurrence, where the schema is {}: JSON Schema output here has no $ref, so the repeated level is left open.
A type with no JSON representation (a raw time.Duration, channels, functions, complex numbers, unsafe pointers, or map keys of other kinds) makes the schema invalid: Err returns an error wrapping ErrInvalidSchema naming the path, and JSONSchema, Validate and Parse return it. Infer itself never panics, so it is safe in package-level variables for types the caller does not control.
Example:
type Result struct {
Name string `json:"name"`
Elapsed validate.Duration `json:"elapsed"`
Note string `json:"note,omitempty"`
}
doc, err := validate.Infer[Result]().JSONSchema()
// {"properties":{"elapsed":{"format":"go-duration","type":"string"},
// "name":{"type":"string"},"note":{"type":"string"}},
// "required":["name","elapsed"],"type":"object"}
func (InferSchema[T]) Err ¶
func (schema InferSchema[T]) Err() error
Err returns the error that made the schema invalid, or nil. It wraps ErrInvalidSchema.
Example:
schema := validate.Infer[string]()
if err := schema.Err(); err != nil {
panic(err)
}
func (InferSchema[T]) JSONSchema ¶
func (schema InferSchema[T]) JSONSchema() ([]byte, error)
JSONSchema renders the inferred type document, without inspecting a value or executing application code. It returns the inference error for an invalid definition. Inferred metadata does not add runtime value constraints.
Example:
schema := validate.Infer[string]()
document, err := schema.JSONSchema()
if err != nil {
panic(err)
}
_ = document
func (InferSchema[T]) Parse ¶
func (schema InferSchema[T]) Parse(ctx context.Context, v T) (T, error)
Parse returns v unchanged when the definition and context are valid. It does not copy or normalize arbitrary values. An inference or context error returns the zero value and the same error as InferSchema.Validate.
Example:
schema := validate.Infer[string]()
value, err := schema.Parse(context.Background(), "Ada")
if err != nil {
panic(err)
}
_ = value
func (InferSchema[T]) Validate ¶
func (schema InferSchema[T]) Validate(ctx context.Context, _ T) error
Validate returns InferSchema.Err for an invalid definition, otherwise the context error or nil. It applies no value rules, defaults or normalization and does not fields.Inspect or modify the supplied value.
Example:
schema := validate.Infer[string]()
if err := schema.Validate(context.Background(), "Ada"); err != nil {
panic(err)
}
type IntBuilder ¶
type IntBuilder[N signed] struct {
// contains filtered or unexported fields
}
IntBuilder configures a detached IntSchema during construction. Settings return the same draft. Retaining a draft cannot change a schema; concurrent mutation of a draft is not supported.
Example:
var configure validate.IntBuilderFunc[int] = func(rules *validate.IntBuilder[int]) {
rules.Required()
}
_ = configure
func (*IntBuilder[N]) Abs ¶
func (number *IntBuilder[N]) Abs() *IntBuilder[N]
Abs replaces a negative value with its absolute value. The minimum value of a signed type has no positive counterpart and stays unchanged. It is a normalizer: it runs before presence, Default and every rule, in the order written.
Example:
schema := validate.Int(func(number *validate.IntBuilder[int]) {
number.Abs()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*IntBuilder[N]) Bail ¶
func (draft *IntBuilder[N]) Bail() *IntBuilder[N]
Bail stops checking this value at its first failure. By default every failure is reported.
Example:
type Value struct {
Name string
}
type Form struct {
Value int
Peer int
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.IntBuilder[int]) {
rules.Bail()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*IntBuilder[N]) Between ¶
func (number *IntBuilder[N]) Between(low, high N) *IntBuilder[N]
Between requires a value from low to high, inclusive.
Example:
schema := validate.Int(func(number *validate.IntBuilder[int]) {
number.Between(1, 100)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*IntBuilder[N]) Check ¶
func (draft *IntBuilder[N]) Check(fn func(context.Context, N) error) *IntBuilder[N]
Check adds a custom rule that runs only for present values. Return Fail (or At in a Struct check) to report a violation; any other error aborts validation and is returned to the caller unchanged.
Example:
type Value struct {
Name string
}
type Form struct {
Value int
Peer int
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.IntBuilder[int]) {
rules.Check(func(_ context.Context, value int) error {
return nil
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*IntBuilder[N]) Clamp ¶
func (number *IntBuilder[N]) Clamp(low, high N) *IntBuilder[N]
Clamp limits the value to the range from low to high. It panics with ErrInvalidSchema when low is greater than high. It is a normalizer: it runs before presence, Default and every rule, in the order written.
Example:
schema := validate.Int(func(number *validate.IntBuilder[int]) {
number.Clamp(0, 100)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*IntBuilder[N]) Default ¶
func (draft *IntBuilder[N]) Default(value N) *IntBuilder[N]
Default sets the value Parse uses when the prepared input is absent. Registered defaults are checked while a Struct is built; standalone defaults are checked by execution, not metadata export. Input normalizers run before default selection and do not run again on the selected default. Arbitrary default objects retain application ownership. Default cannot be combined with Required.
Example:
type Value struct {
Name string
}
type Form struct {
Value int
Peer int
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.IntBuilder[int]) {
rules.Default(3)
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*IntBuilder[N]) Describe ¶
func (draft *IntBuilder[N]) Describe(text string) *IntBuilder[N]
Describe sets the human-readable description that JSONSchema renders as "description". It does not affect validation. Use it for field and tool descriptions.
Example:
type Value struct {
Name string
}
type Form struct {
Value int
Peer int
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.IntBuilder[int]) {
rules.Describe("A display value")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*IntBuilder[N]) EqField ¶
func (draft *IntBuilder[N]) EqField(field string) *IntBuilder[N]
EqField requires the value to equal the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value int
Peer int
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.IntBuilder[int]) {
rules.EqField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*IntBuilder[N]) ExcludeIf ¶
func (draft *IntBuilder[N]) ExcludeIf(configure ...ConditionBuilderFunc) *IntBuilder[N]
ExcludeIf treats the value as absent, and clears it, when the conditions hold. Later ordinary value constraints skip absence, but later presence constraints still observe it and can report violations. Unconditional preparation may already have run before this rule is evaluated.
Example:
type Value struct {
Name string
}
type Form struct {
Value int
Peer int
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.IntBuilder[int]) {
rules.ExcludeIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*IntBuilder[N]) Gt ¶
func (number *IntBuilder[N]) Gt(limit N) *IntBuilder[N]
Gt requires a value greater than limit.
Example:
schema := validate.Int(func(number *validate.IntBuilder[int]) {
number.Gt(1)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*IntBuilder[N]) GtField ¶
func (number *IntBuilder[N]) GtField(field string) *IntBuilder[N]
GtField requires a value greater than the sibling field of the same type.
Example:
type Bounds struct {
Low, High int
}
schema := validate.Struct(func(object *validate.StructBuilder[Bounds]) {
object.Field("High", func(number *validate.IntBuilder[int]) {
number.GtField("Low")
})
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*IntBuilder[N]) Gte ¶
func (number *IntBuilder[N]) Gte(limit N) *IntBuilder[N]
Gte requires a value greater than or equal to limit.
Example:
schema := validate.Int(func(number *validate.IntBuilder[int]) {
number.Gte(1)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*IntBuilder[N]) GteField ¶
func (number *IntBuilder[N]) GteField(field string) *IntBuilder[N]
GteField requires a value greater than or equal to the sibling field.
Example:
type Bounds struct {
Low, High int
}
schema := validate.Struct(func(object *validate.StructBuilder[Bounds]) {
object.Field("High", func(number *validate.IntBuilder[int]) {
number.GteField("Low")
})
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*IntBuilder[N]) Lt ¶
func (number *IntBuilder[N]) Lt(limit N) *IntBuilder[N]
Lt requires a value less than limit.
Example:
schema := validate.Int(func(number *validate.IntBuilder[int]) {
number.Lt(100)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*IntBuilder[N]) LtField ¶
func (number *IntBuilder[N]) LtField(field string) *IntBuilder[N]
LtField requires a value less than the sibling field.
Example:
type Bounds struct {
Low, High int
}
schema := validate.Struct(func(object *validate.StructBuilder[Bounds]) {
object.Field("Low", func(number *validate.IntBuilder[int]) {
number.LtField("High")
})
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*IntBuilder[N]) Lte ¶
func (number *IntBuilder[N]) Lte(limit N) *IntBuilder[N]
Lte requires a value less than or equal to limit.
Example:
schema := validate.Int(func(number *validate.IntBuilder[int]) {
number.Lte(100)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*IntBuilder[N]) LteField ¶
func (number *IntBuilder[N]) LteField(field string) *IntBuilder[N]
LteField requires a value less than or equal to the sibling field.
Example:
type Bounds struct {
Low, High int
}
schema := validate.Struct(func(object *validate.StructBuilder[Bounds]) {
object.Field("Low", func(number *validate.IntBuilder[int]) {
number.LteField("High")
})
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*IntBuilder[N]) Max ¶
func (number *IntBuilder[N]) Max(limit N) *IntBuilder[N]
Max allows at most limit.
Example:
schema := validate.Int(func(number *validate.IntBuilder[int]) {
number.Max(100)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*IntBuilder[N]) Min ¶
func (number *IntBuilder[N]) Min(limit N) *IntBuilder[N]
Min requires at least limit.
Example:
schema := validate.Int(func(number *validate.IntBuilder[int]) {
number.Min(1)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*IntBuilder[N]) MultipleOf ¶
func (number *IntBuilder[N]) MultipleOf(factor N) *IntBuilder[N]
MultipleOf requires a multiple of a strictly positive factor; validated values may be negative. Zero retains its immediate ErrInvalidSchema panic. A negative factor records a sticky construction diagnostic: Struct aggregates it with field errors, standalone execution panics with ErrInvalidSchema, and JSONSchema returns an error wrapping that sentinel. Callbacks still finish.
Example:
schema := validate.Int(func(number *validate.IntBuilder[int]) {
number.MultipleOf(5)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*IntBuilder[N]) NeField ¶
func (draft *IntBuilder[N]) NeField(field string) *IntBuilder[N]
NeField requires the value to differ from the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value int
Peer int
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.IntBuilder[int]) {
rules.NeField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*IntBuilder[N]) NonNegative ¶
func (number *IntBuilder[N]) NonNegative() *IntBuilder[N]
NonNegative requires a value of zero or more.
Example:
schema := validate.Int(func(number *validate.IntBuilder[int]) {
number.NonNegative()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*IntBuilder[N]) Normalize ¶
func (draft *IntBuilder[N]) Normalize(fn func(N) N) *IntBuilder[N]
Normalize adds a custom normalizer. It runs before the presence check, Default and every rule, in the order written among the normalizers. It must return the value it is given or a new one, and must not modify its argument. Normalize cannot be used on Map key schemas.
Example:
type Value struct {
Name string
}
type Form struct {
Value int
Peer int
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.IntBuilder[int]) {
rules.Normalize(func(value int) int {
return value
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*IntBuilder[N]) NotOneOf ¶
func (number *IntBuilder[N]) NotOneOf(values ...N) *IntBuilder[N]
NotOneOf rejects the listed values.
Example:
schema := validate.Int(func(number *validate.IntBuilder[int]) {
number.NotOneOf(13)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*IntBuilder[N]) OneOf ¶
func (number *IntBuilder[N]) OneOf(values ...N) *IntBuilder[N]
OneOf accepts only the listed values.
Example:
schema := validate.Int(func(number *validate.IntBuilder[int]) {
number.OneOf(1, 2, 3)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*IntBuilder[N]) Positive ¶
func (number *IntBuilder[N]) Positive() *IntBuilder[N]
Positive requires a value greater than zero.
Example:
schema := validate.Int(func(number *validate.IntBuilder[int]) {
number.Positive()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*IntBuilder[N]) ProhibitedIf ¶
func (draft *IntBuilder[N]) ProhibitedIf(configure ...ConditionBuilderFunc) *IntBuilder[N]
ProhibitedIf fails when the value is present and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value int
Peer int
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.IntBuilder[int]) {
rules.ProhibitedIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*IntBuilder[N]) ProhibitedUnless ¶
func (draft *IntBuilder[N]) ProhibitedUnless(configure ...ConditionBuilderFunc) *IntBuilder[N]
ProhibitedUnless fails when the value is present and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value int
Peer int
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.IntBuilder[int]) {
rules.ProhibitedUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*IntBuilder[N]) Required ¶
func (draft *IntBuilder[N]) Required() *IntBuilder[N]
Required fails when the value is absent. Absent means zero, or nil for pointers, slices and maps. It cannot be combined with Default.
Example:
type Value struct {
Name string
}
type Form struct {
Value int
Peer int
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.IntBuilder[int]) {
rules.Required()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*IntBuilder[N]) RequiredIf ¶
func (draft *IntBuilder[N]) RequiredIf(configure ...ConditionBuilderFunc) *IntBuilder[N]
RequiredIf fails when the value is absent and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value int
Peer int
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.IntBuilder[int]) {
rules.RequiredIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*IntBuilder[N]) RequiredUnless ¶
func (draft *IntBuilder[N]) RequiredUnless(configure ...ConditionBuilderFunc) *IntBuilder[N]
RequiredUnless fails when the value is absent and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value int
Peer int
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.IntBuilder[int]) {
rules.RequiredUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*IntBuilder[N]) RequiredWith ¶
func (draft *IntBuilder[N]) RequiredWith(fields ...string) *IntBuilder[N]
RequiredWith fails when the value is absent and any of the sibling fields is present.
Example:
type Value struct {
Name string
}
type Form struct {
Value int
Peer int
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.IntBuilder[int]) {
rules.RequiredWith("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*IntBuilder[N]) RequiredWithAll ¶
func (draft *IntBuilder[N]) RequiredWithAll(fields ...string) *IntBuilder[N]
RequiredWithAll fails when the value is absent and all of the sibling fields are present.
Example:
type Value struct {
Name string
}
type Form struct {
Value int
Peer int
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.IntBuilder[int]) {
rules.RequiredWithAll("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*IntBuilder[N]) RequiredWithout ¶
func (draft *IntBuilder[N]) RequiredWithout(fields ...string) *IntBuilder[N]
RequiredWithout fails when the value is absent and any of the sibling fields is absent.
Example:
type Value struct {
Name string
}
type Form struct {
Value int
Peer int
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.IntBuilder[int]) {
rules.RequiredWithout("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*IntBuilder[N]) Use ¶
func (draft *IntBuilder[N]) Use(schema Schema[N]) *IntBuilder[N]
Use adds rules from the same published schema role, as a value or nonnil pointer, before subsequent local settings. InferSchema contributes type-only documentation, not validation or missing child definitions. FromJSONSchema provides a separate decoded-JSON API, not a Schema value accepted here. Other schema roles are rejected even when their value type matches, because importing only their base could lose child rules. Schema-level rules accumulate. Overlapping child definitions are construction errors, and later local child callbacks cannot replace an imported child. Ptr permits an unconstrained scalar adapter to yield to a shared pointee. The source remains immutable. Typed nil pointers wrap ErrInvalidSchema.
Example:
var configure validate.IntBuilderFunc[int] = func(rules *validate.IntBuilder[int]) {
rules.Use(validate.Int[int]())
}
_ = configure
func (*IntBuilder[N]) When ¶
func (draft *IntBuilder[N]) When(condition ConditionBuilderFunc, configure ...func(*IntBuilder[N])) *IntBuilder[N]
When applies additional rules when the condition holds for the enclosing struct. The extra schema runs in place, in the order written, and sees defaults and exclusions like the rest of the chain.
Example:
type Value struct {
Name string
}
type Form struct {
Value int
Peer int
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.IntBuilder[int]) {
rules.When(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
}, func(selected *validate.IntBuilder[int]) {
selected.Required()
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
type IntBuilderFunc ¶
type IntBuilderFunc[N signed] = func(*IntBuilder[N])
IntBuilderFunc edits one temporary IntBuilder. Constructors invoke callbacks once, synchronously in order; a nil supplied callback panics.
Example:
var configure validate.IntBuilderFunc[int] = func(rules *validate.IntBuilder[int]) {
rules.Required()
}
_ = configure
type IntSchema ¶
type IntSchema[N signed] struct {
// contains filtered or unexported fields
}
IntSchema validates signed integers, including named types. Construct it with Int and configure its IntBuilder; the published value is immutable.
WARNING: zero counts as absent and skips every rule except Required, so an optional schema configured with Min(1) accepts 0. Use Required or Ptr when zero is a meaningful value that must be range-checked.
Example:
schema := validate.Int(func(number *validate.IntBuilder[int]) {
number.Min(1)
})
if err := schema.Validate(context.Background(), 3); err != nil {
panic(err)
}
func Int ¶
func Int[N signed](configure ...IntBuilderFunc[N]) IntSchema[N]
Int publishes a schema for signed N, inferred from typed callbacks. Each callback edits one fresh draft once in order; publication detaches its rules.
Example:
schema := validate.Int(func(number *validate.IntBuilder[int64]) {
number.Positive()
})
if err := schema.Validate(context.Background(), 12); err != nil {
panic(err)
}
func (IntSchema[N]) JSONSchema ¶
JSONSchema renders this schema's supported JSON Schema constraints. Runtime-only rules remain enforced by Parse and Validate; invalid schema definitions or values that JSON cannot encode return an error. As with StringSchema.JSONSchema, definition checks never execute validation callbacks; recorded construction errors wrap ErrInvalidSchema.
Example:
schema := validate.Int[int]()
document, err := schema.JSONSchema()
if err != nil {
panic(err)
}
_ = document
func (IntSchema[N]) Parse ¶
Parse checks the input and returns its normalized, defaulted result. It copies storage before applying schema changes and returns the zero value with Errors or a custom Check error when validation fails.
Example:
schema := validate.Int[int]()
value, err := schema.Parse(context.Background(), 3)
if err != nil {
panic(err)
}
_ = value
func (IntSchema[N]) Validate ¶
Validate checks the input using the same preparation and rules as Parse, without returning the prepared value. It returns nil, Errors, or a custom Check error; caller-owned input is not modified.
Example:
schema := validate.Int[int]()
if err := schema.Validate(context.Background(), 3); err != nil {
panic(err)
}
type JSONSchema ¶
type JSONSchema struct {
// contains filtered or unexported fields
}
JSONSchema validates decoded JSON values against a JSON Schema document. Create one with FromJSONSchema; the zero value is not usable. Like the other schemas it is immutable and safe for concurrent use.
Values are the ones encoding/json/v2 decodes into an any: map[string]any, []any, string, float64, bool and nil. Go int and int64 and valid numeric encoding/json/jsontext.Value tokens are also accepted as numbers. Other Go types match no "type" and are not checked by kind-specific keywords. Input must be acyclic. uniqueItems requires finite numbers and these JSON-like types throughout each item; other values report "type" at that item's pointer instead of using an unbounded fallback.
uniqueItems uses exact structural keys, including sorted object keys. For n fixed-size scalar items, expected work and key storage are O(n), including when maxItems is absent. Nested values add their encoded size and O(k log k) sorting per object of k keys. Numeric items compare by their exact decimal value at every nesting level, without changing concrete Go input values. Keys describe pre-default items. See JSONSchema.Parse for cancellation and oversized-array behavior.
Imported numeric literals retain their exact decimal value and spelling for bounds, multipleOf, enum, const, and schema export. Go floats are interpreted as their shortest decimal JSON encoding; precision lost before Parse cannot be recovered. Numeric defaults and diagnostic parameters use float64 only when its JSON spelling preserves that value; otherwise they use an owned jsontext.Value. Existing Go numeric inputs retain their concrete types. Very large exponents outside math/big's supported range are schema errors. Bound untrusted document size and numeric magnitude as well as input size.
The semantics are those of JSON Schema, with these choices:
- null is absent, as nil is elsewhere in this package: it satisfies every keyword, whatever "type" says, and is replaced by "default" in Parse. A key listed in "required" must be present in the object, and null counts as present.
- Zero values are values. Unlike Struct, where false, 0 and "" are absent and skip rules, a "minLength" of 3 rejects "". Likewise "required" is about the key, so "" and 0 satisfy it.
- Keywords apply to the kinds they belong to and are ignored for the others, so "minLength" without "type" only checks strings.
- "format" checks date-time (RFC 3339), email, uri (absolute, with a host), uuid, duration (RFC 3339 Appendix A) and go-duration (time.ParseDuration). Other formats, including binary, are annotations and accept any string.
Example:
check, err := validate.FromJSONSchema([]byte(`{"uniqueItems":true,"maxItems":100}`))
if err != nil {
return err
}
return check.Validate(ctx, []any{"blue", "green"})
func FromJSONSchema ¶
func FromJSONSchema(doc []byte) (JSONSchema, error)
FromJSONSchema builds a validator for decoded JSON values from a JSON Schema document. It accepts the following self-contained keyword subset; this is not a general JSON Schema implementation or a guarantee that every exported definition can be imported unchanged:
type, properties, required, additionalProperties, items, enum, const, default, description, format, pattern, minLength, maxLength, minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf, minItems, maxItems, uniqueItems, minProperties, maxProperties
"type" is a single string (string, integer, number, boolean, object or array): the package never renders type arrays, because nil is not modeled. "integer" rejects numbers with a fractional part. Anything else is an error rather than being ignored, so a document that depends on a keyword the validator would skip cannot pass for checked: FromJSONSchema returns an error wrapping ErrInvalidSchema that names the keyword and its JSON Pointer location, such as `unsupported keyword "$ref" at "/properties/a"`. The same error reports a keyword with a value of the wrong type, a pattern that does not compile, or a default that fails its own schema. Required names must be unique strings; an empty property name is valid. Numeric literals are kept exactly rather than decoded through float64.
Export omits runtime normalizers and checks and does not verify defaults. Import therefore need not accept an exported default that violates the emitted constraints, and it cannot reproduce omitted runtime behavior. Import retains the application-oriented null/default rules of JSONSchema; it is not strict validation of an already encoded instance.
Violations are keyed by the JSON Pointer of the offending value and use the codes of the equivalent rule ("string.min", "number.max", "slice.unique", "required", "one_of", ...), so messages translate through the same Catalog. A value of the wrong kind reports "type", and a date-time string that does not parse reports "type" with the expected value "RFC 3339 date-time". Rules that Struct enforces but JSON Schema cannot express (field comparisons, conditions, Check) are not in the document and are not checked.
"pattern" must be a string; an empty pattern matches every string. Patterns use Go regular expressions (RE2), which can differ from the ECMA 262 dialect that JSON Schema names.
Example:
check, err := validate.FromJSONSchema(doc)
if err != nil {
return err // unsupported keyword or malformed document
}
if err := check.Validate(ctx, decoded); err != nil {
errs, ok := errors.AsType[validate.Errors](err)
if !ok {
return err // canceled context or deadline
}
// errs["/items/0/name"][0].Code == "string.min"
return errs
}
func (JSONSchema) JSONSchema ¶
func (schema JSONSchema) JSONSchema() ([]byte, error)
JSONSchema renders the accepted document with sorted object keys and the original spelling of numeric literals. It does not run validation or default insertion. This is deterministic rendering, not RFC 8785 canonicalization: equivalent numeric spellings such as 1.0 and 1e0 remain distinct in the output.
Example:
schema, err := validate.FromJSONSchema([]byte(`{"type":"string"}`))
if err != nil {
panic(err)
}
document, err := schema.JSONSchema()
if err != nil {
panic(err)
}
_ = document
func (JSONSchema) Parse ¶
Parse runs the checks of JSONSchema.Validate and also returns a deep copy of v with defaults applied: a property that is missing or null takes its "default", as does a null value anywhere else that has one. v is never modified. On failure the result is nil. After the type check, an array exceeding maxItems reports only slice.max for that array, skipping its other checks and children; validation of sibling values still continues.
Traversal, equality checks, structural uniqueness keys, object-key sorting, and copying observe ctx cancellation. Cancellation returns ctx.Err() unchanged and discards any accumulated violations. Individual scalar checks (such as a regexp match) and runtime allocations are not preempted. Input must be acyclic; bound document size and nesting before validation.
Example:
check, err := validate.FromJSONSchema([]byte(`{"type":"string","default":"free"}`))
if err != nil {
return err
}
parsed, err := check.Parse(ctx, nil) // parsed is "free" on success
func (JSONSchema) Validate ¶
func (schema JSONSchema) Validate(ctx context.Context, v any) error
Validate checks the decoded JSON value v and returns nil, or an Errors keyed by JSON Pointer. See JSONSchema for the value types and FromJSONSchema for the codes. v is never modified. Cancellation returns ctx.Err() instead of any accumulated violations; see JSONSchema.Parse for traversal and size limits.
Example:
check, err := validate.FromJSONSchema([]byte(`{"type":"array","maxItems":100}`))
if err != nil {
return err
}
return check.Validate(ctx, []any{1.0, 2.0})
type JSONTypeProvider ¶
type JSONTypeProvider interface {
// JSONSchemaType returns the identical unnamed slice or map type. Infer
// invokes it on a fresh non-nil pointer to the zero value, before inspecting
// custom JSON or text marshalers. The method must be deterministic, pure,
// and independent of receiver contents. A nil result, mismatched type, or
// panic becomes an error wrapping ErrInvalidSchema. Native byte slices
// describe base64 strings. Encoding options and nil formatting are not modeled.
//
// Example:
//
// var provider validate.JSONTypeProvider = collection.Slice[int](nil)
// fmt.Println(provider.JSONSchemaType() == reflect.TypeFor[[]int]()) // true
JSONSchemaType() reflect.Type
}
JSONTypeProvider explicitly declares that a named slice or map uses the JSON shape of its identical unnamed container type, despite custom JSON methods. Infer recognizes the protocol structurally; implementations need not import validate. Arbitrary custom marshalers without this opt-in remain opaque.
Example:
var provider validate.JSONTypeProvider = collection.Slice[string](nil) fmt.Println(provider.JSONSchemaType() == reflect.TypeFor[[]string]()) // true
type MapBuilder ¶
type MapBuilder[K comparable, V any] struct { // contains filtered or unexported fields }
MapBuilder configures a detached MapSchema during construction. Settings return the same draft. Retaining a draft cannot change a schema; concurrent mutation of a draft is not supported.
Example:
var configure validate.MapBuilderFunc[string, string] = func(rules *validate.MapBuilder[string, string]) {
rules.Required()
}
_ = configure
func (*MapBuilder[K, V]) Bail ¶
func (draft *MapBuilder[K, V]) Bail() *MapBuilder[K, V]
Bail stops checking this value at its first failure. By default every failure is reported.
Example:
type Value struct {
Name string
}
type Form struct {
Value map[string]string
Peer map[string]string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.MapBuilder[string, string]) {
rules.Bail()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*MapBuilder[K, V]) Check ¶
func (draft *MapBuilder[K, V]) Check(fn func(context.Context, map[K]V) error) *MapBuilder[K, V]
Check adds a custom rule that runs only for present values. Return Fail (or At in a Struct check) to report a violation; any other error aborts validation and is returned to the caller unchanged.
Example:
type Value struct {
Name string
}
type Form struct {
Value map[string]string
Peer map[string]string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.MapBuilder[string, string]) {
rules.Check(func(_ context.Context, value map[string]string) error {
return nil
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*MapBuilder[K, V]) Contains ¶
func (entries *MapBuilder[K, V]) Contains(match func(K, V) bool) *MapBuilder[K, V]
Contains requires a matching map entry in sorted key order. Key and value always come from one entry. Empty maps fail; nil optional maps skip the rule.
Example:
schema := validate.Map(func(entries *validate.MapBuilder[string, int]) {
entries.Contains(func(key string, value int) bool {
return key == "admin" && value > 0
})
})
_ = schema
func (*MapBuilder[K, V]) CountWhere ¶
func (entries *MapBuilder[K, V]) CountWhere(match func(K, V) bool, configure ...IntBuilderFunc[int]) *MapBuilder[K, V]
CountWhere validates the matching entry count with forced presence. Only pure numeric constraints are allowed; invalid settings fail construction.
Example:
schema := validate.Map(func(entries *validate.MapBuilder[string, int]) {
entries.CountWhere(func(key string, value int) bool {
return value > 0
}, func(count *validate.IntBuilder[int]) {
count.Max(3)
})
})
_ = schema
func (*MapBuilder[K, V]) Default ¶
func (entries *MapBuilder[K, V]) Default(value map[K]V) *MapBuilder[K, V]
Default sets the map used by Parse when the input is nil. Each result gets its own copy.
Example:
schema := validate.Map(func(entries *validate.MapBuilder[string, int]) {
entries.Default(map[string]int{"age": 0})
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*MapBuilder[K, V]) Describe ¶
func (draft *MapBuilder[K, V]) Describe(text string) *MapBuilder[K, V]
Describe sets the human-readable description that JSONSchema renders as "description". It does not affect validation. Use it for field and tool descriptions.
Example:
type Value struct {
Name string
}
type Form struct {
Value map[string]string
Peer map[string]string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.MapBuilder[string, string]) {
rules.Describe("A display value")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*MapBuilder[K, V]) EqField ¶
func (draft *MapBuilder[K, V]) EqField(field string) *MapBuilder[K, V]
EqField requires the value to equal the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value map[string]string
Peer map[string]string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.MapBuilder[string, string]) {
rules.EqField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*MapBuilder[K, V]) Every ¶
func (entries *MapBuilder[K, V]) Every(match func(K, V) bool) *MapBuilder[K, V]
Every reports each failing map key separately in deterministic order. Empty maps pass vacuously. Match must not mutate values or their reachable data.
Example:
schema := validate.Map(func(entries *validate.MapBuilder[string, int]) {
entries.Every(func(key string, value int) bool {
return value >= 0
})
})
_ = schema
func (*MapBuilder[K, V]) ExcludeIf ¶
func (draft *MapBuilder[K, V]) ExcludeIf(configure ...ConditionBuilderFunc) *MapBuilder[K, V]
ExcludeIf treats the value as absent, and clears it, when the conditions hold. Later ordinary value constraints skip absence, but later presence constraints still observe it and can report violations. Unconditional preparation may already have run before this rule is evaluated.
Example:
type Value struct {
Name string
}
type Form struct {
Value map[string]string
Peer map[string]string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.MapBuilder[string, string]) {
rules.ExcludeIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*MapBuilder[K, V]) Has ¶
func (entries *MapBuilder[K, V]) Has(key K) *MapBuilder[K, V]
Has requires key existence, independent of the stored value's presence. Nil optional maps skip the rule; allocated empty maps fail.
Example:
schema := validate.Map(func(entries *validate.MapBuilder[string, int]) {
entries.Has("admin")
})
_ = schema
func (*MapBuilder[K, V]) HasAll ¶
func (entries *MapBuilder[K, V]) HasAll(keys ...K) *MapBuilder[K, V]
HasAll requires every listed key. The input list is copied; an empty list passes vacuously. Values at existing keys may be zero.
Example:
schema := validate.Map(func(entries *validate.MapBuilder[string, int]) {
entries.HasAll("name", "age")
})
_ = schema
func (*MapBuilder[K, V]) HasAny ¶
func (entries *MapBuilder[K, V]) HasAny(keys ...K) *MapBuilder[K, V]
HasAny requires at least one listed key. The input list is copied and an empty list always fails for a present map, regardless of stored zero values.
Example:
schema := validate.Map(func(entries *validate.MapBuilder[string, int]) {
entries.HasAny("admin", "editor")
})
_ = schema
func (*MapBuilder[K, V]) Keys ¶
func (entries *MapBuilder[K, V]) Keys[D any, P draftPointer[D]](configure ...ChildBuilderFunc[P]) *MapBuilder[K, V]
Keys defines the exact key schema of a map. Key normalization is rejected when the resulting schema is compiled, because it would change identity. Local Keys calls replace earlier local keys, but cannot replace Use imports.
Example:
schema := validate.Map[string, int](func(entries *validate.MapBuilder[string, int]) {
entries.Keys(func(key *validate.StringBuilder[string]) {
key.Min(1)
})
entries.Values(func(value *validate.IntBuilder[int]) {
value.Positive()
})
})
_ = schema
func (*MapBuilder[K, V]) Len ¶
func (entries *MapBuilder[K, V]) Len(size int) *MapBuilder[K, V]
Len requires exactly size entries, annotating minProperties and maxProperties in JSON Schema. Keys count even when their stored values are zero.
Example:
schema := validate.Map(func(entries *validate.MapBuilder[string, int]) {
entries.Len(2)
})
_ = schema
func (*MapBuilder[K, V]) Max ¶
func (entries *MapBuilder[K, V]) Max(n int) *MapBuilder[K, V]
Max allows at most n entries.
Example:
schema := validate.Map(func(entries *validate.MapBuilder[string, int]) {
entries.Max(10)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*MapBuilder[K, V]) Min ¶
func (entries *MapBuilder[K, V]) Min(n int) *MapBuilder[K, V]
Min requires at least n entries.
Example:
schema := validate.Map(func(entries *validate.MapBuilder[string, int]) {
entries.Min(1)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*MapBuilder[K, V]) NeField ¶
func (draft *MapBuilder[K, V]) NeField(field string) *MapBuilder[K, V]
NeField requires the value to differ from the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value map[string]string
Peer map[string]string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.MapBuilder[string, string]) {
rules.NeField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*MapBuilder[K, V]) Normalize ¶
func (draft *MapBuilder[K, V]) Normalize(fn func(map[K]V) map[K]V) *MapBuilder[K, V]
Normalize adds a custom normalizer. It runs before the presence check, Default and every rule, in the order written among the normalizers. It must return the value it is given or a new one, and must not modify its argument. Normalize cannot be used on Map key schemas.
Example:
type Value struct {
Name string
}
type Form struct {
Value map[string]string
Peer map[string]string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.MapBuilder[string, string]) {
rules.Normalize(func(value map[string]string) map[string]string {
return value
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*MapBuilder[K, V]) ProhibitedIf ¶
func (draft *MapBuilder[K, V]) ProhibitedIf(configure ...ConditionBuilderFunc) *MapBuilder[K, V]
ProhibitedIf fails when the value is present and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value map[string]string
Peer map[string]string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.MapBuilder[string, string]) {
rules.ProhibitedIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*MapBuilder[K, V]) ProhibitedUnless ¶
func (draft *MapBuilder[K, V]) ProhibitedUnless(configure ...ConditionBuilderFunc) *MapBuilder[K, V]
ProhibitedUnless fails when the value is present and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value map[string]string
Peer map[string]string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.MapBuilder[string, string]) {
rules.ProhibitedUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*MapBuilder[K, V]) Required ¶
func (draft *MapBuilder[K, V]) Required() *MapBuilder[K, V]
Required fails when the value is absent. Absent means zero, or nil for pointers, slices and maps. It cannot be combined with Default.
Example:
type Value struct {
Name string
}
type Form struct {
Value map[string]string
Peer map[string]string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.MapBuilder[string, string]) {
rules.Required()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*MapBuilder[K, V]) RequiredIf ¶
func (draft *MapBuilder[K, V]) RequiredIf(configure ...ConditionBuilderFunc) *MapBuilder[K, V]
RequiredIf fails when the value is absent and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value map[string]string
Peer map[string]string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.MapBuilder[string, string]) {
rules.RequiredIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*MapBuilder[K, V]) RequiredUnless ¶
func (draft *MapBuilder[K, V]) RequiredUnless(configure ...ConditionBuilderFunc) *MapBuilder[K, V]
RequiredUnless fails when the value is absent and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value map[string]string
Peer map[string]string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.MapBuilder[string, string]) {
rules.RequiredUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*MapBuilder[K, V]) RequiredWith ¶
func (draft *MapBuilder[K, V]) RequiredWith(fields ...string) *MapBuilder[K, V]
RequiredWith fails when the value is absent and any of the sibling fields is present.
Example:
type Value struct {
Name string
}
type Form struct {
Value map[string]string
Peer map[string]string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.MapBuilder[string, string]) {
rules.RequiredWith("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*MapBuilder[K, V]) RequiredWithAll ¶
func (draft *MapBuilder[K, V]) RequiredWithAll(fields ...string) *MapBuilder[K, V]
RequiredWithAll fails when the value is absent and all of the sibling fields are present.
Example:
type Value struct {
Name string
}
type Form struct {
Value map[string]string
Peer map[string]string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.MapBuilder[string, string]) {
rules.RequiredWithAll("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*MapBuilder[K, V]) RequiredWithout ¶
func (draft *MapBuilder[K, V]) RequiredWithout(fields ...string) *MapBuilder[K, V]
RequiredWithout fails when the value is absent and any of the sibling fields is absent.
Example:
type Value struct {
Name string
}
type Form struct {
Value map[string]string
Peer map[string]string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.MapBuilder[string, string]) {
rules.RequiredWithout("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*MapBuilder[K, V]) UniqueBy ¶
func (entries *MapBuilder[K, V]) UniqueBy[U comparable](project func(K, V) U) *MapBuilder[K, V]
UniqueBy requires distinct comparable projections in sorted map-key order. Each duplicate fails at its key with the first conflicting key in parameters.
Example:
schema := validate.Map(func(entries *validate.MapBuilder[string, int]) {
entries.UniqueBy(func(key string, value int) int {
return value
})
})
_ = schema
func (*MapBuilder[K, V]) Use ¶
func (draft *MapBuilder[K, V]) Use(schema Schema[map[K]V]) *MapBuilder[K, V]
Use adds rules from the same published schema role, as a value or nonnil pointer, before subsequent local settings. InferSchema contributes type-only documentation, not validation or missing child definitions. FromJSONSchema provides a separate decoded-JSON API, not a Schema value accepted here. Other schema roles are rejected even when their value type matches, because importing only their base could lose child rules. Schema-level rules accumulate. Overlapping child definitions are construction errors, and later local child callbacks cannot replace an imported child. Ptr permits an unconstrained scalar adapter to yield to a shared pointee. The source remains immutable. Typed nil pointers wrap ErrInvalidSchema.
Example:
var configure validate.MapBuilderFunc[string, string] = func(rules *validate.MapBuilder[string, string]) {
rules.Use(validate.Map[string, string]())
}
_ = configure
func (*MapBuilder[K, V]) Values ¶
func (entries *MapBuilder[K, V]) Values[D any, P draftPointer[D]](configure ...ChildBuilderFunc[P]) *MapBuilder[K, V]
Values defines the exact value schema of a map. The fresh child draft is published immediately, so later changes to a retained child do not leak. Local Values calls replace earlier local values, but cannot replace Use imports.
Example:
schema := validate.Map[string, int](func(entries *validate.MapBuilder[string, int]) {
entries.Keys(func(key *validate.StringBuilder[string]) {
})
entries.Values(func(value *validate.IntBuilder[int]) {
value.Min(1)
})
})
_ = schema
func (*MapBuilder[K, V]) When ¶
func (draft *MapBuilder[K, V]) When(condition ConditionBuilderFunc, configure ...func(*MapBuilder[K, V])) *MapBuilder[K, V]
When applies additional rules when the condition holds for the enclosing struct. The extra schema runs in place, in the order written, and sees defaults and exclusions like the rest of the chain.
Example:
type Value struct {
Name string
}
type Form struct {
Value map[string]string
Peer map[string]string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.MapBuilder[string, string]) {
rules.When(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
}, func(selected *validate.MapBuilder[string, string]) {
selected.Required()
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
type MapBuilderFunc ¶
type MapBuilderFunc[K comparable, V any] = func(*MapBuilder[K, V])
MapBuilderFunc edits one temporary MapBuilder. Constructors invoke callbacks once, synchronously in order; a nil supplied callback panics.
Example:
var configure validate.MapBuilderFunc[string, string] = func(rules *validate.MapBuilder[string, string]) {
rules.Required()
}
_ = configure
type MapSchema ¶
type MapSchema[K comparable, V any] struct { // contains filtered or unexported fields }
MapSchema validates maps, their keys and their values. Create one with Map. A nil map is absent; an empty non-nil map is present. Keys and values are always present. A zero MapSchema is uninitialized. Use Map even when only collection-level rules are needed, and configure settings on its temporary MapBuilder.
Example:
schema := validate.Map(func(entries *validate.MapBuilder[string, int]) {
entries.Has("age")
})
if err := schema.Validate(context.Background(), map[string]int{"age": 0}); err != nil {
panic(err)
}
func Map ¶
func Map[K comparable, V any](configure ...MapBuilderFunc[K, V]) MapSchema[K, V]
Map publishes a schema for map[K]V. Callbacks run once in order; Keys and Values optionally add exact-type child validation. Retained drafts cannot change the result. Entry violations extend the collection pointer by key, with entries visited in sorted diagnostic-name order. JSON-compatible keys use their JSON-v2 object name, including custom JSON and text marshaling. Other Go keys retain fmt.Sprint names; validation does not require JSON encodability. Different keys with the same name share a diagnostic path and retain every violation, but their relative order is unspecified. Key marshalers must be deterministic, concurrency-safe and must not mutate keys.
Example:
schema := validate.Map(func(entries *validate.MapBuilder[string, int]) {
entries.Keys(func(key *validate.StringBuilder[string]) {
key.Min(1)
})
entries.Values(func(number *validate.IntBuilder[int]) {
number.Min(0)
})
})
if err := schema.Validate(context.Background(), map[string]int{"age": 0}); err != nil {
panic(err)
}
func (MapSchema[K, V]) JSONSchema ¶
JSONSchema renders this schema's supported JSON Schema constraints. Runtime-only rules remain enforced by Parse and Validate; invalid schema definitions or values that JSON cannot encode return an error. Definition checks include keys even though key rules are not exported. They never execute validation callbacks; definition errors wrap ErrInvalidSchema.
Example:
schema := validate.Map[string, int]()
document, err := schema.JSONSchema()
if err != nil {
panic(err)
}
_ = document
func (MapSchema[K, V]) Parse ¶
Parse checks the input and returns its normalized, defaulted result. It copies storage before applying schema changes and returns the zero value with Errors or a custom Check error when validation fails.
Example:
schema := validate.Map[string, int]()
value, err := schema.Parse(context.Background(), map[string]int{"age": 3})
if err != nil {
panic(err)
}
_ = value
func (MapSchema[K, V]) Validate ¶
Validate checks the input using the same preparation and rules as Parse, without returning the prepared value. It returns nil, Errors, or a custom Check error; caller-owned input is not modified.
Example:
schema := validate.Map[string, int]()
if err := schema.Validate(context.Background(), map[string]int{"age": 3}); err != nil {
panic(err)
}
type Messages ¶
Messages maps a violation code to a message template. Templates may contain {param} placeholders that are replaced with violation params.
type NamedBuilder ¶
type NamedBuilder[T any] struct { // contains filtered or unexported fields }
NamedBuilder attaches an existing slice or map schema to its named container type T. It supplies only type adaptation; configure rules on the source schema. A fresh draft is selected by Field, Values, or Value like other drafts. Retaining a draft cannot change a published schema.
Example:
type Names []string
type Request struct { Names Names }
schema := validate.Struct(func(object *validate.StructBuilder[Request]) {
object.Field("Names", func(names *validate.NamedBuilder[Names]) {
names.Use(validate.Slice[string]())
})
})
_ = schema
func (*NamedBuilder[T]) Use ¶
func (named *NamedBuilder[T]) Use[U any](schema Schema[U]) *NamedBuilder[T]
Use attaches one immutable container schema. Repeated attachments are rejected rather than silently replacing rules. Source schema pointers are snapshotted as values; nil sources remain invalid definitions, not omitted validation.
Example:
type Names []string
type Request struct { Names Names }
schema := validate.Struct(func(object *validate.StructBuilder[Request]) {
object.Field("Names", func(names *validate.NamedBuilder[Names]) {
names.Use(validate.Slice[string]())
})
})
_ = schema
type NamedBuilderFunc ¶
type NamedBuilderFunc[T any] = func(*NamedBuilder[T])
NamedBuilderFunc configures one NamedBuilder during construction. Its alias identity accepts ordinary function values and slices without conversion.
Example:
type Names []string
var configure validate.NamedBuilderFunc[Names] = func(names *validate.NamedBuilder[Names]) {
names.Use(validate.Slice[string]())
}
_ = configure
type NamedSchema ¶
type NamedSchema[T any] struct { // contains filtered or unexported fields }
NamedSchema adapts a schema to an identical named slice or map type. It preserves source presence, defaults, normalization, errors, and JSON Schema metadata. It does not infer custom JSON encoding; use Infer for wire metadata. A zero NamedSchema is invalid. Published adapters are safe for concurrent use under the same callback-ownership rules as their source schemas.
Example:
type Names []string
schema := validate.Named[Names](validate.Slice[string]())
values, err := schema.Parse(context.Background(), Names{"Ada"})
if err != nil {
panic(err)
}
_ = values
func Named ¶
func Named[T, U any](inner Schema[U]) NamedSchema[T]
Named adapts inner to the named slice or map T without converting elements or keys. T and the source must have identical underlying container types; scalar conversions and element-wise conversions are rejected. The source need not be unnamed. To register a named field, use a NamedBuilder callback. Invalid definitions follow Schema's normal export/error and execution/panic behavior. Parsing preserves T and never mutates caller-owned storage.
Example:
type Names []string
schema := validate.Named[Names](validate.Slice(func(items *validate.SliceBuilder[string]) {
items.Values(func(name *validate.StringBuilder[string]) {
name.Trim().Min(1)
})
}))
values, err := schema.Parse(context.Background(), Names{" Ada "})
if err != nil {
panic(err)
}
fmt.Println(values[0]) // Ada
func (NamedSchema[T]) JSONSchema ¶
func (schema NamedSchema[T]) JSONSchema() ([]byte, error)
JSONSchema renders the source's supported constraints, not inferred custom encoding. Invalid adapters return an error wrapping ErrInvalidSchema.
Example:
type Names []string
document, err := validate.Named[Names](validate.Slice[string]()).JSONSchema()
if err != nil {
panic(err)
}
_ = document
func (NamedSchema[T]) Parse ¶
func (schema NamedSchema[T]) Parse(ctx context.Context, value T) (T, error)
Parse validates a copied T through the source execution plan and returns its normalized named result. Failure returns zero T and the source error. Invalid adapters panic with ErrInvalidSchema during compilation.
Example:
type Names []string
values, err := validate.Named[Names](validate.Slice[string]()).Parse(context.Background(), Names{"Ada"})
if err != nil {
panic(err)
}
_ = values
func (NamedSchema[T]) Validate ¶
func (schema NamedSchema[T]) Validate(ctx context.Context, value T) error
Validate performs the same preparation and checks as Parse without returning a normalized value. Caller-owned containers are not modified.
Example:
type Names []string
err := validate.Named[Names](validate.Slice[string]()).Validate(context.Background(), Names{"Ada"})
if err != nil {
panic(err)
}
type PtrBuilder ¶
type PtrBuilder[T any] struct { // contains filtered or unexported fields }
PtrBuilder configures a detached PtrSchema during construction. Settings return the same draft. Retaining a draft cannot change a schema; concurrent mutation of a draft is not supported.
Example:
var configure validate.PtrBuilderFunc[string] = func(rules *validate.PtrBuilder[string]) {
rules.Required()
}
_ = configure
func (*PtrBuilder[T]) Bail ¶
func (draft *PtrBuilder[T]) Bail() *PtrBuilder[T]
Bail stops checking this value at its first failure. By default every failure is reported.
Example:
type Value struct {
Name string
}
type Form struct {
Value *string
Peer *string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.PtrBuilder[string]) {
rules.Value(func(value *validate.StringBuilder[string]) {
})
rules.Bail()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*PtrBuilder[T]) Check ¶
func (draft *PtrBuilder[T]) Check(fn func(context.Context, *T) error) *PtrBuilder[T]
Check adds a custom rule that runs only for present values. Return Fail (or At in a Struct check) to report a violation; any other error aborts validation and is returned to the caller unchanged.
Example:
type Value struct {
Name string
}
type Form struct {
Value *string
Peer *string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.PtrBuilder[string]) {
rules.Value(func(value *validate.StringBuilder[string]) {
})
rules.Check(func(_ context.Context, value *string) error {
return nil
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*PtrBuilder[T]) Default ¶
func (pointer *PtrBuilder[T]) Default(value T) *PtrBuilder[T]
Default sets the value used by Parse when the pointer is nil. Each result gets its own pointer to a copy of value.
Example:
schema := validate.Ptr(validate.String[string](), func(pointer *validate.PtrBuilder[string]) {
pointer.Default("Ada")
})
value, err := schema.Parse(context.Background(), nil)
if err != nil {
panic(err)
}
fmt.Println(*value)
func (*PtrBuilder[T]) Describe ¶
func (draft *PtrBuilder[T]) Describe(text string) *PtrBuilder[T]
Describe sets the human-readable description that JSONSchema renders as "description". It does not affect validation. Use it for field and tool descriptions.
Example:
type Value struct {
Name string
}
type Form struct {
Value *string
Peer *string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.PtrBuilder[string]) {
rules.Value(func(value *validate.StringBuilder[string]) {
})
rules.Describe("A display value")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*PtrBuilder[T]) EqField ¶
func (draft *PtrBuilder[T]) EqField(field string) *PtrBuilder[T]
EqField requires the value to equal the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value *string
Peer *string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.PtrBuilder[string]) {
rules.Value(func(value *validate.StringBuilder[string]) {
})
rules.EqField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*PtrBuilder[T]) ExcludeIf ¶
func (draft *PtrBuilder[T]) ExcludeIf(configure ...ConditionBuilderFunc) *PtrBuilder[T]
ExcludeIf treats the value as absent, and clears it, when the conditions hold. Later ordinary value constraints skip absence, but later presence constraints still observe it and can report violations. Unconditional preparation may already have run before this rule is evaluated.
Example:
type Value struct {
Name string
}
type Form struct {
Value *string
Peer *string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.PtrBuilder[string]) {
rules.Value(func(value *validate.StringBuilder[string]) {
})
rules.ExcludeIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*PtrBuilder[T]) NeField ¶
func (draft *PtrBuilder[T]) NeField(field string) *PtrBuilder[T]
NeField requires the value to differ from the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value *string
Peer *string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.PtrBuilder[string]) {
rules.Value(func(value *validate.StringBuilder[string]) {
})
rules.NeField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*PtrBuilder[T]) Normalize ¶
func (draft *PtrBuilder[T]) Normalize(fn func(*T) *T) *PtrBuilder[T]
Normalize adds a custom normalizer. It runs before the presence check, Default and every rule, in the order written among the normalizers. It must return the value it is given or a new one, and must not modify its argument. Normalize cannot be used on Map key schemas.
Example:
type Value struct {
Name string
}
type Form struct {
Value *string
Peer *string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.PtrBuilder[string]) {
rules.Value(func(value *validate.StringBuilder[string]) {
})
rules.Normalize(func(value *string) *string {
return value
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*PtrBuilder[T]) ProhibitedIf ¶
func (draft *PtrBuilder[T]) ProhibitedIf(configure ...ConditionBuilderFunc) *PtrBuilder[T]
ProhibitedIf fails when the value is present and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value *string
Peer *string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.PtrBuilder[string]) {
rules.Value(func(value *validate.StringBuilder[string]) {
})
rules.ProhibitedIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*PtrBuilder[T]) ProhibitedUnless ¶
func (draft *PtrBuilder[T]) ProhibitedUnless(configure ...ConditionBuilderFunc) *PtrBuilder[T]
ProhibitedUnless fails when the value is present and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value *string
Peer *string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.PtrBuilder[string]) {
rules.Value(func(value *validate.StringBuilder[string]) {
})
rules.ProhibitedUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*PtrBuilder[T]) Required ¶
func (draft *PtrBuilder[T]) Required() *PtrBuilder[T]
Required fails when the value is absent. Absent means zero, or nil for pointers, slices and maps. It cannot be combined with Default.
Example:
type Value struct {
Name string
}
type Form struct {
Value *string
Peer *string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.PtrBuilder[string]) {
rules.Value(func(value *validate.StringBuilder[string]) {
})
rules.Required()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*PtrBuilder[T]) RequiredIf ¶
func (draft *PtrBuilder[T]) RequiredIf(configure ...ConditionBuilderFunc) *PtrBuilder[T]
RequiredIf fails when the value is absent and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value *string
Peer *string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.PtrBuilder[string]) {
rules.Value(func(value *validate.StringBuilder[string]) {
})
rules.RequiredIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*PtrBuilder[T]) RequiredUnless ¶
func (draft *PtrBuilder[T]) RequiredUnless(configure ...ConditionBuilderFunc) *PtrBuilder[T]
RequiredUnless fails when the value is absent and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value *string
Peer *string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.PtrBuilder[string]) {
rules.Value(func(value *validate.StringBuilder[string]) {
})
rules.RequiredUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*PtrBuilder[T]) RequiredWith ¶
func (draft *PtrBuilder[T]) RequiredWith(fields ...string) *PtrBuilder[T]
RequiredWith fails when the value is absent and any of the sibling fields is present.
Example:
type Value struct {
Name string
}
type Form struct {
Value *string
Peer *string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.PtrBuilder[string]) {
rules.Value(func(value *validate.StringBuilder[string]) {
})
rules.RequiredWith("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*PtrBuilder[T]) RequiredWithAll ¶
func (draft *PtrBuilder[T]) RequiredWithAll(fields ...string) *PtrBuilder[T]
RequiredWithAll fails when the value is absent and all of the sibling fields are present.
Example:
type Value struct {
Name string
}
type Form struct {
Value *string
Peer *string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.PtrBuilder[string]) {
rules.Value(func(value *validate.StringBuilder[string]) {
})
rules.RequiredWithAll("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*PtrBuilder[T]) RequiredWithout ¶
func (draft *PtrBuilder[T]) RequiredWithout(fields ...string) *PtrBuilder[T]
RequiredWithout fails when the value is absent and any of the sibling fields is absent.
Example:
type Value struct {
Name string
}
type Form struct {
Value *string
Peer *string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.PtrBuilder[string]) {
rules.Value(func(value *validate.StringBuilder[string]) {
})
rules.RequiredWithout("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*PtrBuilder[T]) Use ¶
func (draft *PtrBuilder[T]) Use(schema Schema[*T]) *PtrBuilder[T]
Use adds rules from the same published schema role, as a value or nonnil pointer, before subsequent local settings. InferSchema contributes type-only documentation, not validation or missing child definitions. FromJSONSchema provides a separate decoded-JSON API, not a Schema value accepted here. Other schema roles are rejected even when their value type matches, because importing only their base could lose child rules. Schema-level rules accumulate. Overlapping child definitions are construction errors, and later local child callbacks cannot replace an imported child. Ptr permits an unconstrained scalar adapter to yield to a shared pointee. The source remains immutable. Typed nil pointers wrap ErrInvalidSchema.
Example:
var configure validate.PtrBuilderFunc[string] = func(rules *validate.PtrBuilder[string]) {
rules.Use(validate.Ptr(validate.String[string]()))
}
_ = configure
func (*PtrBuilder[T]) Value ¶
func (pointer *PtrBuilder[T]) Value[D any, P draftPointer[D]](configure ...ChildBuilderFunc[P]) *PtrBuilder[T]
Value defines a pointer's exact pointee schema. A nonnil pointer forces its pointee present, so zero values still receive the child rules. Value replaces a local positional adapter or earlier local Value definition. It cannot replace a pointee imported by Use, which would discard shared rules.
Example:
schema := validate.Ptr(validate.Int[int](), func(pointer *validate.PtrBuilder[int]) {
pointer.Value(func(value *validate.IntBuilder[int]) {
value.Min(0)
})
})
_ = schema
func (*PtrBuilder[T]) When ¶
func (draft *PtrBuilder[T]) When(condition ConditionBuilderFunc, configure ...func(*PtrBuilder[T])) *PtrBuilder[T]
When applies additional rules when the condition holds for the enclosing struct. The extra schema runs in place, in the order written, and sees defaults and exclusions like the rest of the chain.
Example:
type Value struct {
Name string
}
type Form struct {
Value *string
Peer *string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.PtrBuilder[string]) {
rules.Value(func(value *validate.StringBuilder[string]) {
})
rules.When(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
}, func(selected *validate.PtrBuilder[string]) {
selected.Required()
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
type PtrBuilderFunc ¶
type PtrBuilderFunc[T any] = func(*PtrBuilder[T])
PtrBuilderFunc edits one temporary PtrBuilder. Constructors invoke callbacks once, synchronously in order; a nil supplied callback panics.
Example:
var configure validate.PtrBuilderFunc[string] = func(rules *validate.PtrBuilder[string]) {
rules.Required()
}
_ = configure
type PtrSchema ¶
type PtrSchema[T any] struct { // contains filtered or unexported fields }
PtrSchema validates a pointer and the value it points to. Create one with Ptr. A nil pointer is absent; a pointer to a zero value is present, which makes Ptr the way to accept false, 0 or "" as real values. Settings belong to PtrBuilder; published schemas expose no configuration.
Example:
schema := validate.Ptr(validate.Int(func(number *validate.IntBuilder[int]) {
number.Min(0)
}))
value := 0
if err := schema.Validate(context.Background(), &value); err != nil {
panic(err)
}
func Ptr ¶
func Ptr[T any](inner Schema[T], configure ...PtrBuilderFunc[T]) PtrSchema[T]
Ptr returns a schema for *T that validates the pointee with inner. Violations are reported at the pointer's own path. Callbacks run once in order after the explicit inner schema is attached. Value can replace the pointee definition; Use imports an exact *T schema. Nil inner schemas without a replacement are construction errors. Non-nil schema pointers are captured as values after the callbacks finish; reassigning the caller's schema variable cannot change the published rules.
Example:
schema := validate.Ptr(validate.String[string](), func(pointer *validate.PtrBuilder[string]) {
pointer.Required()
})
value := ""
if err := schema.Validate(context.Background(), &value); err != nil {
panic(err)
}
func (PtrSchema[T]) JSONSchema ¶
JSONSchema renders this schema's supported JSON Schema constraints. Runtime-only rules remain enforced by Parse and Validate; invalid schema definitions or values that JSON cannot encode return an error. Definition checks include the pointee without executing validation callbacks; recorded construction errors wrap ErrInvalidSchema.
Example:
schema := validate.Ptr(validate.String[string]())
document, err := schema.JSONSchema()
if err != nil {
panic(err)
}
_ = document
func (PtrSchema[T]) Parse ¶
Parse checks the input and returns its normalized, defaulted result. It copies storage before applying schema changes and returns the zero value with Errors or a custom Check error when validation fails.
Example:
schema := validate.Ptr(validate.String[string]())
value, err := schema.Parse(context.Background(), nil)
if err != nil {
panic(err)
}
_ = value
func (PtrSchema[T]) Validate ¶
Validate checks the input using the same preparation and rules as Parse, without returning the prepared value. It returns nil, Errors, or a custom Check error; caller-owned input is not modified.
Example:
schema := validate.Ptr(validate.String[string]())
if err := schema.Validate(context.Background(), nil); err != nil {
panic(err)
}
type Schema ¶
type Schema[T any] interface { // Validate checks the prepared v and returns nil, [Errors], or a Check // error. Invalid explicit definitions panic during standalone compilation; // they are not returned as violations. Caller-owned input is not modified. // // Example: // // schema := validate.String[string]() // if err := schema.Validate(context.Background(), "Ada"); err != nil { // panic(err) // } Validate(ctx context.Context, v T) error // Parse checks v and returns its normalized, defaulted copy. A validation // failure returns the zero T and an error, never a partial result. Invalid // explicit definitions panic during standalone compilation, as with Validate. // // Example: // // schema := validate.String(func(text *validate.StringBuilder[string]) { // text.Trim() // }) // value, err := schema.Parse(context.Background(), " Ada ") // if err != nil { // panic(err) // } // fmt.Println(value) // Ada Parse(ctx context.Context, v T) (T, error) // JSONSchema renders the schema as a JSON Schema document (2020-12 // subset). Rules JSON Schema cannot express (EqField and the other // field comparisons, conditions, Check functions, normalizers, and // time- or clock-based rules) are left out; they are still enforced by // Validate and Parse. A successful export describes supported constraints; // it does not prove equivalence with a decoded-JSON validator. // // The output is deterministic: object keys are sorted. Invalid definitions // return nil bytes and an error wrapping [ErrInvalidSchema], including // recorded Use errors, invalid rule arguments, unbound field references, // and unconstructed composite schemas. A zero [StructSchema] is invalid // even through [Ptr]; use Struct[T]() for a valid empty registration. // Constructed slice and map schemas may omit child rules deliberately. // Values JSON cannot encode, such as a non-JSON default, instead return // nil bytes and an error preserving the JSON encoder's cause. // // Export checks definitions without running Check, Normalize, condition, // or collection-predicate callbacks, and never replays construction callbacks. // It does not verify defaults against their rules or normalize default // annotations. Repeated annotations use the last value while runtime rules // accumulate. Go absence semantics and numeric representation also limit // interchange; consumers must check their own import and validation results. // // Example: // // type Signup struct { // Email string // } // schema := validate.Struct(func(object *validate.StructBuilder[Signup]) { // object.Field("Email", func(email *validate.StringBuilder[string]) { // email.Email() // }) // }) // document, err := schema.JSONSchema() // if err != nil { // panic(err) // } // fmt.Println(string(document)) JSONSchema() ([]byte, error) // contains filtered or unexported methods }
Schema validates values of type T. Build schemas with String, Int, Struct and the other constructors in this package.
Validate checks v and returns nil when it passes, an Errors when rules fail, or any other error returned by a Check function. Parse runs the same checks and also returns a copy of v with defaults applied; the input is never modified. Both agree on pass or fail. Cancellation stops between normalization, rule and child callbacks and returns the context error unless an earlier operational error already aborted execution. Parse discards partial results in either case. For explicit builder-backed schemas, standalone compilation panics with an error wrapping ErrInvalidSchema if the definition is invalid; this is not a user-input violation. InferSchema instead returns its inference error.
Schemas expose execution and inspection only and are safe to share between concurrent calls. Settings belong to typed construction drafts, not schemas. Drafts do not implement Schema. External schema implementations are prohibited. Schema-owned state is immutable; arbitrary defaults, native objects and function captures are not recursively copied and must be safe for shared use.
Example:
var schema validate.Schema[string] = validate.String(func(text *validate.StringBuilder[string]) {
text.Trim().Required()
})
value, err := schema.Parse(context.Background(), " Ada ")
if err != nil {
panic(err)
}
fmt.Println(value)
type SliceBuilder ¶
type SliceBuilder[E any] struct { // contains filtered or unexported fields }
SliceBuilder configures a detached SliceSchema during construction. Settings return the same draft. Retaining a draft cannot change a schema; concurrent mutation of a draft is not supported.
Example:
var configure validate.SliceBuilderFunc[string] = func(rules *validate.SliceBuilder[string]) {
rules.Required()
}
_ = configure
func (*SliceBuilder[E]) Bail ¶
func (draft *SliceBuilder[E]) Bail() *SliceBuilder[E]
Bail stops checking this value at its first failure. By default every failure is reported.
Example:
type Value struct {
Name string
}
type Form struct {
Value []string
Peer []string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.SliceBuilder[string]) {
rules.Bail()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*SliceBuilder[E]) Check ¶
func (draft *SliceBuilder[E]) Check(fn func(context.Context, []E) error) *SliceBuilder[E]
Check adds a custom rule that runs only for present values. Return Fail (or At in a Struct check) to report a violation; any other error aborts validation and is returned to the caller unchanged.
Example:
type Value struct {
Name string
}
type Form struct {
Value []string
Peer []string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.SliceBuilder[string]) {
rules.Check(func(_ context.Context, value []string) error {
return nil
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*SliceBuilder[E]) Contains ¶
func (items *SliceBuilder[E]) Contains(match func(int, E) bool) *SliceBuilder[E]
Contains requires a matching normalized slice entry. An allocated empty slice fails; nil optional slices skip the assertion. Match must be pure.
Example:
schema := validate.Slice(func(items *validate.SliceBuilder[int]) {
items.Contains(func(index, value int) bool {
return value > 0
})
})
_ = schema
func (*SliceBuilder[E]) CountWhere ¶
func (items *SliceBuilder[E]) CountWhere(match func(int, E) bool, configure ...IntBuilderFunc[int]) *SliceBuilder[E]
CountWhere validates the matching entry count. Zero is always present. Only pure numeric constraints are allowed, not defaults, normalization, presence, field references, conditions or operational Check functions.
Example:
schema := validate.Slice(func(items *validate.SliceBuilder[int]) {
items.CountWhere(func(index, value int) bool {
return value > 0
}, func(count *validate.IntBuilder[int]) {
count.Min(1)
})
})
_ = schema
func (*SliceBuilder[E]) Dedupe ¶
func (items *SliceBuilder[E]) Dedupe() *SliceBuilder[E]
Dedupe drops repeated elements, keeping the first occurrence and the order. E must be comparable; Dedupe panics with ErrInvalidSchema otherwise. It is a normalizer, see Sort.
Example:
schema := validate.Slice(func(items *validate.SliceBuilder[string]) {
items.Dedupe()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*SliceBuilder[E]) Default ¶
func (items *SliceBuilder[E]) Default(value []E) *SliceBuilder[E]
Default sets the slice used by Parse when the input is nil. Each result gets its own copy.
Example:
schema := validate.Slice(func(items *validate.SliceBuilder[string]) {
items.Default([]string{"Ada"})
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*SliceBuilder[E]) Describe ¶
func (draft *SliceBuilder[E]) Describe(text string) *SliceBuilder[E]
Describe sets the human-readable description that JSONSchema renders as "description". It does not affect validation. Use it for field and tool descriptions.
Example:
type Value struct {
Name string
}
type Form struct {
Value []string
Peer []string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.SliceBuilder[string]) {
rules.Describe("A display value")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*SliceBuilder[E]) EqField ¶
func (draft *SliceBuilder[E]) EqField(field string) *SliceBuilder[E]
EqField requires the value to equal the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value []string
Peer []string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.SliceBuilder[string]) {
rules.EqField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*SliceBuilder[E]) Every ¶
func (items *SliceBuilder[E]) Every(match func(int, E) bool) *SliceBuilder[E]
Every checks every normalized entry and reports each failing index. Empty slices pass vacuously. Match must not mutate observed values.
Example:
schema := validate.Slice(func(items *validate.SliceBuilder[int]) {
items.Every(func(index, value int) bool {
return value >= 0
})
})
_ = schema
func (*SliceBuilder[E]) ExcludeIf ¶
func (draft *SliceBuilder[E]) ExcludeIf(configure ...ConditionBuilderFunc) *SliceBuilder[E]
ExcludeIf treats the value as absent, and clears it, when the conditions hold. Later ordinary value constraints skip absence, but later presence constraints still observe it and can report violations. Unconditional preparation may already have run before this rule is evaluated.
Example:
type Value struct {
Name string
}
type Form struct {
Value []string
Peer []string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.SliceBuilder[string]) {
rules.ExcludeIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*SliceBuilder[E]) Filter ¶
func (items *SliceBuilder[E]) Filter(keep func(int, E) bool) *SliceBuilder[E]
Filter keeps the elements for which keep returns true. The callback receives the index and the element, like the foundation/collection Slice.Filter. The result is a new slice, empty but non-nil for a non-nil input, so it stays present. It is a normalizer, see Sort.
Example:
schema := validate.Slice(func(items *validate.SliceBuilder[string]) {
items.Filter(func(index int, value string) bool {
return value != ""
})
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*SliceBuilder[E]) Len ¶
func (items *SliceBuilder[E]) Len(n int) *SliceBuilder[E]
Len requires exactly n elements.
Example:
schema := validate.Slice(func(items *validate.SliceBuilder[string]) {
items.Len(2)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*SliceBuilder[E]) Max ¶
func (items *SliceBuilder[E]) Max(n int) *SliceBuilder[E]
Max allows at most n elements.
Example:
schema := validate.Slice(func(items *validate.SliceBuilder[string]) {
items.Max(10)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*SliceBuilder[E]) Min ¶
func (items *SliceBuilder[E]) Min(n int) *SliceBuilder[E]
Min requires at least n elements.
Example:
schema := validate.Slice(func(items *validate.SliceBuilder[string]) {
items.Min(1)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*SliceBuilder[E]) NeField ¶
func (draft *SliceBuilder[E]) NeField(field string) *SliceBuilder[E]
NeField requires the value to differ from the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value []string
Peer []string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.SliceBuilder[string]) {
rules.NeField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*SliceBuilder[E]) Normalize ¶
func (draft *SliceBuilder[E]) Normalize(fn func([]E) []E) *SliceBuilder[E]
Normalize adds a custom normalizer. It runs before the presence check, Default and every rule, in the order written among the normalizers. It must return the value it is given or a new one, and must not modify its argument. Normalize cannot be used on Map key schemas.
Example:
type Value struct {
Name string
}
type Form struct {
Value []string
Peer []string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.SliceBuilder[string]) {
rules.Normalize(func(value []string) []string {
return value
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*SliceBuilder[E]) ProhibitedIf ¶
func (draft *SliceBuilder[E]) ProhibitedIf(configure ...ConditionBuilderFunc) *SliceBuilder[E]
ProhibitedIf fails when the value is present and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value []string
Peer []string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.SliceBuilder[string]) {
rules.ProhibitedIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*SliceBuilder[E]) ProhibitedUnless ¶
func (draft *SliceBuilder[E]) ProhibitedUnless(configure ...ConditionBuilderFunc) *SliceBuilder[E]
ProhibitedUnless fails when the value is present and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value []string
Peer []string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.SliceBuilder[string]) {
rules.ProhibitedUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*SliceBuilder[E]) Reject ¶
func (items *SliceBuilder[E]) Reject(drop func(int, E) bool) *SliceBuilder[E]
Reject drops the elements for which drop returns true. It is the opposite of Filter. It is a normalizer, see Sort.
Example:
schema := validate.Slice(func(items *validate.SliceBuilder[string]) {
items.Reject(func(index int, value string) bool {
return value == ""
})
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*SliceBuilder[E]) RejectZero ¶
func (items *SliceBuilder[E]) RejectZero() *SliceBuilder[E]
RejectZero drops the elements that are the zero value of E. The result is empty but non-nil for a non-nil input, so RejectZero().Min(1) fails for []string{"", ""}. It is a normalizer, see Sort.
Example:
schema := validate.Slice(func(items *validate.SliceBuilder[string]) {
items.RejectZero()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*SliceBuilder[E]) Required ¶
func (draft *SliceBuilder[E]) Required() *SliceBuilder[E]
Required fails when the value is absent. Absent means zero, or nil for pointers, slices and maps. It cannot be combined with Default.
Example:
type Value struct {
Name string
}
type Form struct {
Value []string
Peer []string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.SliceBuilder[string]) {
rules.Required()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*SliceBuilder[E]) RequiredIf ¶
func (draft *SliceBuilder[E]) RequiredIf(configure ...ConditionBuilderFunc) *SliceBuilder[E]
RequiredIf fails when the value is absent and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value []string
Peer []string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.SliceBuilder[string]) {
rules.RequiredIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*SliceBuilder[E]) RequiredUnless ¶
func (draft *SliceBuilder[E]) RequiredUnless(configure ...ConditionBuilderFunc) *SliceBuilder[E]
RequiredUnless fails when the value is absent and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value []string
Peer []string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.SliceBuilder[string]) {
rules.RequiredUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*SliceBuilder[E]) RequiredWith ¶
func (draft *SliceBuilder[E]) RequiredWith(fields ...string) *SliceBuilder[E]
RequiredWith fails when the value is absent and any of the sibling fields is present.
Example:
type Value struct {
Name string
}
type Form struct {
Value []string
Peer []string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.SliceBuilder[string]) {
rules.RequiredWith("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*SliceBuilder[E]) RequiredWithAll ¶
func (draft *SliceBuilder[E]) RequiredWithAll(fields ...string) *SliceBuilder[E]
RequiredWithAll fails when the value is absent and all of the sibling fields are present.
Example:
type Value struct {
Name string
}
type Form struct {
Value []string
Peer []string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.SliceBuilder[string]) {
rules.RequiredWithAll("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*SliceBuilder[E]) RequiredWithout ¶
func (draft *SliceBuilder[E]) RequiredWithout(fields ...string) *SliceBuilder[E]
RequiredWithout fails when the value is absent and any of the sibling fields is absent.
Example:
type Value struct {
Name string
}
type Form struct {
Value []string
Peer []string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.SliceBuilder[string]) {
rules.RequiredWithout("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*SliceBuilder[E]) Sort ¶
func (items *SliceBuilder[E]) Sort(cmp func(E, E) int) *SliceBuilder[E]
Sort orders the elements with cmp, keeping equal elements in their original order. It sorts a copy. It is a normalizer: it runs after the element normalizers and before presence, Default and every rule, in the order written among the slice normalizers. A nil slice stays nil.
Example:
schema := validate.Slice(func(items *validate.SliceBuilder[string]) {
items.Sort(strings.Compare)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*SliceBuilder[E]) Unique ¶
func (items *SliceBuilder[E]) Unique() *SliceBuilder[E]
Unique requires distinct elements. E must be comparable; Unique panics with ErrInvalidSchema otherwise.
Example:
schema := validate.Slice(func(items *validate.SliceBuilder[string]) {
items.Unique()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*SliceBuilder[E]) UniqueBy ¶
func (items *SliceBuilder[E]) UniqueBy[U comparable](project func(int, E) U) *SliceBuilder[E]
UniqueBy requires distinct comparable projections. Each repeated projection fails at its index with the first conflicting index in violation parameters. Project must not mutate observed values.
Example:
schema := validate.Slice(func(items *validate.SliceBuilder[string]) {
items.UniqueBy(func(index int, value string) int {
return len(value)
})
})
_ = schema
func (*SliceBuilder[E]) Use ¶
func (draft *SliceBuilder[E]) Use(schema Schema[[]E]) *SliceBuilder[E]
Use adds rules from the same published schema role, as a value or nonnil pointer, before subsequent local settings. InferSchema contributes type-only documentation, not validation or missing child definitions. FromJSONSchema provides a separate decoded-JSON API, not a Schema value accepted here. Other schema roles are rejected even when their value type matches, because importing only their base could lose child rules. Schema-level rules accumulate. Overlapping child definitions are construction errors, and later local child callbacks cannot replace an imported child. Ptr permits an unconstrained scalar adapter to yield to a shared pointee. The source remains immutable. Typed nil pointers wrap ErrInvalidSchema.
Example:
var configure validate.SliceBuilderFunc[string] = func(rules *validate.SliceBuilder[string]) {
rules.Use(validate.Slice[string]())
}
_ = configure
func (*SliceBuilder[E]) Values ¶
func (items *SliceBuilder[E]) Values[D any, P draftPointer[D]](configure ...ChildBuilderFunc[P]) *SliceBuilder[E]
Values defines the element schema of a slice using its concrete draft. The element's Go type must be E; callbacks and publication run immediately. Repeated local Values calls replace the local child until Use imports one. Replacing an imported child is an ErrInvalidSchema construction error.
Example:
schema := validate.Slice[string](func(items *validate.SliceBuilder[string]) {
items.Values(func(value *validate.StringBuilder[string]) {
value.Required()
})
})
_ = schema
func (*SliceBuilder[E]) When ¶
func (draft *SliceBuilder[E]) When(condition ConditionBuilderFunc, configure ...func(*SliceBuilder[E])) *SliceBuilder[E]
When applies additional rules when the condition holds for the enclosing struct. The extra schema runs in place, in the order written, and sees defaults and exclusions like the rest of the chain.
Example:
type Value struct {
Name string
}
type Form struct {
Value []string
Peer []string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.SliceBuilder[string]) {
rules.When(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
}, func(selected *validate.SliceBuilder[string]) {
selected.Required()
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
type SliceBuilderFunc ¶
type SliceBuilderFunc[E any] = func(*SliceBuilder[E])
SliceBuilderFunc edits one temporary SliceBuilder. Constructors invoke callbacks once, synchronously in order; a nil supplied callback panics.
Example:
var configure validate.SliceBuilderFunc[string] = func(rules *validate.SliceBuilder[string]) {
rules.Required()
}
_ = configure
type SliceSchema ¶
type SliceSchema[E any] struct { // contains filtered or unexported fields }
SliceSchema validates slices and their elements. Create one with Slice. A nil slice is absent; an empty non-nil slice is present. Elements are always present, so their zero values are checked too. A zero SliceSchema is uninitialized; construct one with Slice, even when per-element rules are omitted. Settings belong to SliceBuilder.
Example:
schema := validate.Slice(func(items *validate.SliceBuilder[string]) {
items.Min(1)
})
if err := schema.Validate(context.Background(), []string{"Ada"}); err != nil {
panic(err)
}
func Slice ¶
func Slice[E any](configure ...SliceBuilderFunc[E]) SliceSchema[E]
Slice publishes a schema for []E. Callbacks run once in order on one fresh draft; Values optionally defines per-element rules. Retained drafts cannot change the result. Entry violations extend the collection pointer by index.
Order: element normalizers run on a copy of every element, then the slice normalizers (Sort, Filter, Reject, RejectZero, Dedupe, Normalize) in written order, then presence, Default and the slice rules, then the element rules. Indices in violations refer to the slice after normalization.
Example:
schema := validate.Slice(func(items *validate.SliceBuilder[string]) {
items.Values(func(text *validate.StringBuilder[string]) {
text.Trim().Min(1)
})
})
value, err := schema.Parse(context.Background(), []string{" Ada "})
if err != nil {
panic(err)
}
fmt.Println(value)
func (SliceSchema[E]) JSONSchema ¶
func (schema SliceSchema[E]) JSONSchema() ([]byte, error)
JSONSchema renders this schema's supported JSON Schema constraints. Runtime-only rules remain enforced by Parse and Validate; invalid schema definitions or values that JSON cannot encode return an error. Definition checks include the element schema without executing validation callbacks; recorded construction errors wrap ErrInvalidSchema.
Example:
schema := validate.Slice[string]()
document, err := schema.JSONSchema()
if err != nil {
panic(err)
}
_ = document
func (SliceSchema[E]) Parse ¶
func (schema SliceSchema[E]) Parse(ctx context.Context, v []E) ([]E, error)
Parse checks the input and returns its normalized, defaulted result. It copies storage before applying schema changes and returns the zero value with Errors or a custom Check error when validation fails.
Example:
schema := validate.Slice[string]()
value, err := schema.Parse(context.Background(), []string{"Ada"})
if err != nil {
panic(err)
}
_ = value
func (SliceSchema[E]) Validate ¶
func (schema SliceSchema[E]) Validate(ctx context.Context, v []E) error
Validate checks the input using the same preparation and rules as Parse, without returning the prepared value. It returns nil, Errors, or a custom Check error; caller-owned input is not modified.
Example:
schema := validate.Slice[string]()
if err := schema.Validate(context.Background(), []string{"Ada"}); err != nil {
panic(err)
}
type StringBuilder ¶
type StringBuilder[S ~string] struct { // contains filtered or unexported fields }
StringBuilder configures a detached StringSchema during construction. Settings return the same draft. Retaining a draft cannot change a schema; concurrent mutation of a draft is not supported.
Example:
var configure validate.StringBuilderFunc[string] = func(rules *validate.StringBuilder[string]) {
rules.Required()
}
_ = configure
func (*StringBuilder[S]) ASCII ¶
func (text *StringBuilder[S]) ASCII() *StringBuilder[S]
ASCII requires every character to be ASCII.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.ASCII()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) Alpha ¶
func (text *StringBuilder[S]) Alpha() *StringBuilder[S]
Alpha requires ASCII letters only.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.Alpha()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) AlphaDash ¶
func (text *StringBuilder[S]) AlphaDash() *StringBuilder[S]
AlphaDash requires ASCII letters, digits, hyphens and underscores only.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.AlphaDash()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) AlphaNumeric ¶
func (text *StringBuilder[S]) AlphaNumeric() *StringBuilder[S]
AlphaNumeric requires ASCII letters and digits only.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.AlphaNumeric()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) Bail ¶
func (draft *StringBuilder[S]) Bail() *StringBuilder[S]
Bail stops checking this value at its first failure. By default every failure is reported.
Example:
type Value struct {
Name string
}
type Form struct {
Value string
Peer string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StringBuilder[string]) {
rules.Bail()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StringBuilder[S]) Check ¶
func (draft *StringBuilder[S]) Check(fn func(context.Context, S) error) *StringBuilder[S]
Check adds a custom rule that runs only for present values. Return Fail (or At in a Struct check) to report a violation; any other error aborts validation and is returned to the caller unchanged.
Example:
type Value struct {
Name string
}
type Form struct {
Value string
Peer string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StringBuilder[string]) {
rules.Check(func(_ context.Context, value string) error {
return nil
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StringBuilder[S]) Contains ¶
func (text *StringBuilder[S]) Contains(substring string) *StringBuilder[S]
Contains requires the string to contain substring.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.Contains("@")
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) Default ¶
func (draft *StringBuilder[S]) Default(value S) *StringBuilder[S]
Default sets the value Parse uses when the prepared input is absent. Registered defaults are checked while a Struct is built; standalone defaults are checked by execution, not metadata export. Input normalizers run before default selection and do not run again on the selected default. Arbitrary default objects retain application ownership. Default cannot be combined with Required.
Example:
type Value struct {
Name string
}
type Form struct {
Value string
Peer string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StringBuilder[string]) {
rules.Default("Ada")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StringBuilder[S]) Describe ¶
func (draft *StringBuilder[S]) Describe(text string) *StringBuilder[S]
Describe sets the human-readable description that JSONSchema renders as "description". It does not affect validation. Use it for field and tool descriptions.
Example:
type Value struct {
Name string
}
type Form struct {
Value string
Peer string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StringBuilder[string]) {
rules.Describe("A display value")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StringBuilder[S]) Domain ¶
func (text *StringBuilder[S]) Domain() *StringBuilder[S]
Domain requires a domain name with at least two labels and an alphabetic top-level domain.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.Domain()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) Duration ¶
func (text *StringBuilder[S]) Duration() *StringBuilder[S]
Duration requires text that time.ParseDuration accepts, such as "182ms", "1.5h" or "-3s". It is the check for a duration received as a string; use Text with Duration for a field that already holds one. Failures use the code "string.duration".
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.Duration()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) Email ¶
func (text *StringBuilder[S]) Email() *StringBuilder[S]
Email requires a bare email address such as "ada@example.com". Display names and comments are rejected.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.Email()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) EqField ¶
func (draft *StringBuilder[S]) EqField(field string) *StringBuilder[S]
EqField requires the value to equal the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value string
Peer string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StringBuilder[string]) {
rules.EqField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StringBuilder[S]) ExcludeIf ¶
func (draft *StringBuilder[S]) ExcludeIf(configure ...ConditionBuilderFunc) *StringBuilder[S]
ExcludeIf treats the value as absent, and clears it, when the conditions hold. Later ordinary value constraints skip absence, but later presence constraints still observe it and can report violations. Unconditional preparation may already have run before this rule is evaluated.
Example:
type Value struct {
Name string
}
type Form struct {
Value string
Peer string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StringBuilder[string]) {
rules.ExcludeIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StringBuilder[S]) IP ¶
func (text *StringBuilder[S]) IP() *StringBuilder[S]
IP requires an IPv4 or IPv6 address without a zone.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.IP()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) Len ¶
func (text *StringBuilder[S]) Len(n int) *StringBuilder[S]
Len requires exactly n runes. A negative n records a construction diagnostic with the same reporting and sticky-error behavior as Min. Zero is valid; use Required separately when empty input must fail the presence check.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.Len(2)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) Lowercase ¶
func (text *StringBuilder[S]) Lowercase() *StringBuilder[S]
Lowercase requires the string to equal its lower case form.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.Lowercase()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) Max ¶
func (text *StringBuilder[S]) Max(n int) *StringBuilder[S]
Max allows at most n runes. A negative n records a construction diagnostic with the same reporting and sticky-error behavior as Min. Zero is valid and rejects every present nonempty string; ordinary absence still skips rules.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.Max(80)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) Min ¶
func (text *StringBuilder[S]) Min(n int) *StringBuilder[S]
Min requires at least n runes. A negative n records a construction diagnostic; Struct reports it with other registration errors, standalone execution panics with ErrInvalidSchema, and JSONSchema returns an error wrapping that sentinel. Later length settings do not clear the diagnostic. Zero is a valid bound.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.Min(3)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) NeField ¶
func (draft *StringBuilder[S]) NeField(field string) *StringBuilder[S]
NeField requires the value to differ from the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value string
Peer string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StringBuilder[string]) {
rules.NeField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StringBuilder[S]) Normalize ¶
func (draft *StringBuilder[S]) Normalize(fn func(S) S) *StringBuilder[S]
Normalize adds a custom normalizer. It runs before the presence check, Default and every rule, in the order written among the normalizers. It must return the value it is given or a new one, and must not modify its argument. Normalize cannot be used on Map key schemas.
Example:
type Value struct {
Name string
}
type Form struct {
Value string
Peer string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StringBuilder[string]) {
rules.Normalize(func(value string) string {
return value
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StringBuilder[S]) NotBlank ¶
func (text *StringBuilder[S]) NotBlank() *StringBuilder[S]
NotBlank rejects strings that contain only white space.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.NotBlank()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) NotOneOf ¶
func (text *StringBuilder[S]) NotOneOf(values ...S) *StringBuilder[S]
NotOneOf rejects the listed values.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.NotOneOf("reserved", "admin")
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) OneOf ¶
func (text *StringBuilder[S]) OneOf(values ...S) *StringBuilder[S]
OneOf accepts only the listed values.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.OneOf("free", "pro")
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) Prefix ¶
func (text *StringBuilder[S]) Prefix(prefix string) *StringBuilder[S]
Prefix requires the string to start with prefix.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.Prefix("https://")
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) ProhibitedIf ¶
func (draft *StringBuilder[S]) ProhibitedIf(configure ...ConditionBuilderFunc) *StringBuilder[S]
ProhibitedIf fails when the value is present and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value string
Peer string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StringBuilder[string]) {
rules.ProhibitedIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StringBuilder[S]) ProhibitedUnless ¶
func (draft *StringBuilder[S]) ProhibitedUnless(configure ...ConditionBuilderFunc) *StringBuilder[S]
ProhibitedUnless fails when the value is present and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value string
Peer string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StringBuilder[string]) {
rules.ProhibitedUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StringBuilder[S]) Regex ¶
func (text *StringBuilder[S]) Regex(pattern *regexp.Regexp) *StringBuilder[S]
Regex requires the string to match pattern.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.Regex(regexp.MustCompile(`^[a-z]+$`))
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) Required ¶
func (draft *StringBuilder[S]) Required() *StringBuilder[S]
Required fails when the value is absent. Absent means zero, or nil for pointers, slices and maps. It cannot be combined with Default.
Example:
type Value struct {
Name string
}
type Form struct {
Value string
Peer string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StringBuilder[string]) {
rules.Required()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StringBuilder[S]) RequiredIf ¶
func (draft *StringBuilder[S]) RequiredIf(configure ...ConditionBuilderFunc) *StringBuilder[S]
RequiredIf fails when the value is absent and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value string
Peer string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StringBuilder[string]) {
rules.RequiredIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StringBuilder[S]) RequiredUnless ¶
func (draft *StringBuilder[S]) RequiredUnless(configure ...ConditionBuilderFunc) *StringBuilder[S]
RequiredUnless fails when the value is absent and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value string
Peer string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StringBuilder[string]) {
rules.RequiredUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StringBuilder[S]) RequiredWith ¶
func (draft *StringBuilder[S]) RequiredWith(fields ...string) *StringBuilder[S]
RequiredWith fails when the value is absent and any of the sibling fields is present.
Example:
type Value struct {
Name string
}
type Form struct {
Value string
Peer string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StringBuilder[string]) {
rules.RequiredWith("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StringBuilder[S]) RequiredWithAll ¶
func (draft *StringBuilder[S]) RequiredWithAll(fields ...string) *StringBuilder[S]
RequiredWithAll fails when the value is absent and all of the sibling fields are present.
Example:
type Value struct {
Name string
}
type Form struct {
Value string
Peer string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StringBuilder[string]) {
rules.RequiredWithAll("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StringBuilder[S]) RequiredWithout ¶
func (draft *StringBuilder[S]) RequiredWithout(fields ...string) *StringBuilder[S]
RequiredWithout fails when the value is absent and any of the sibling fields is absent.
Example:
type Value struct {
Name string
}
type Form struct {
Value string
Peer string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StringBuilder[string]) {
rules.RequiredWithout("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StringBuilder[S]) Suffix ¶
func (text *StringBuilder[S]) Suffix(suffix string) *StringBuilder[S]
Suffix requires the string to end with suffix.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.Suffix(".pdf")
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) ToLower ¶
func (text *StringBuilder[S]) ToLower() *StringBuilder[S]
ToLower lower-cases the whole string. It is a normalizer, see Trim.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.ToLower()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) ToUpper ¶
func (text *StringBuilder[S]) ToUpper() *StringBuilder[S]
ToUpper upper-cases the whole string. It is a normalizer, see Trim.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.ToUpper()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) Trim ¶
func (text *StringBuilder[S]) Trim() *StringBuilder[S]
Trim removes leading and trailing Unicode white space from the value before anything else: before the presence check, before Default and before every rule, wherever Trim appears in the chain. A value that is only white space becomes "" and is absent, so Required fails and Default applies. Conditions and field comparisons on sibling fields see the trimmed value, like they see defaults. Parse returns the trimmed value; Validate checks it but returns nothing, so both agree. The input is never modified. Trim cannot be used on Map key schemas. Like every normalizer it runs in the order written among the other normalizers.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.Trim()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) TrimPrefix ¶
func (text *StringBuilder[S]) TrimPrefix(prefix S) *StringBuilder[S]
TrimPrefix removes one leading prefix when present. It is a normalizer, see Trim.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.TrimPrefix("prefix-")
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) TrimSuffix ¶
func (text *StringBuilder[S]) TrimSuffix(suffix S) *StringBuilder[S]
TrimSuffix removes one trailing suffix when present. It is a normalizer, see Trim.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.TrimSuffix("-suffix")
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) Truncate ¶
func (text *StringBuilder[S]) Truncate(n int) *StringBuilder[S]
Truncate cuts the string to at most n runes. It panics with ErrInvalidSchema when n is negative. It is a normalizer, see Trim.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.Truncate(80)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) URL ¶
func (text *StringBuilder[S]) URL(schemes ...string) *StringBuilder[S]
URL requires an absolute URL with a host and one of the allowed schemes, compared case-insensitively. Without arguments only "http" and "https" are allowed, so values rendered as links cannot carry "javascript:", "data:", or other active schemes. Pass schemes to widen the set, for example URL("https", "ftp"); the argument list replaces the default rather than adding to it. URL copies the list when called, so later changes to the supplied slice cannot change the rule. An empty scheme entry matches no absolute URL; it never permits scheme-relative references such as "//example.com/path". An empty list still selects the defaults.
Failures use the code "string.url". Like other ordinary rules, URL skips absent strings; add Required to reject empty input. JSONSchema exports format "uri", not the scheme restriction or host requirement.
Example:
schemes := []string{"https", "ftp"}
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.URL(schemes...)
})
schemes[0] = "http" // The schema still allows only https and ftp.
if err := schema.Validate(context.Background(), "https://example.com/file"); err != nil {
panic(err)
}
func (*StringBuilder[S]) UUID ¶
func (text *StringBuilder[S]) UUID() *StringBuilder[S]
UUID requires the canonical 8-4-4-4-12 hexadecimal form of any version.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.UUID()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) Uppercase ¶
func (text *StringBuilder[S]) Uppercase() *StringBuilder[S]
Uppercase requires the string to equal its upper case form.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.Uppercase()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StringBuilder[S]) Use ¶
func (draft *StringBuilder[S]) Use(schema Schema[S]) *StringBuilder[S]
Use adds rules from the same published schema role, as a value or nonnil pointer, before subsequent local settings. InferSchema contributes type-only documentation, not validation or missing child definitions. FromJSONSchema provides a separate decoded-JSON API, not a Schema value accepted here. Other schema roles are rejected even when their value type matches, because importing only their base could lose child rules. Schema-level rules accumulate. Overlapping child definitions are construction errors, and later local child callbacks cannot replace an imported child. Ptr permits an unconstrained scalar adapter to yield to a shared pointee. The source remains immutable. Typed nil pointers wrap ErrInvalidSchema.
Example:
var configure validate.StringBuilderFunc[string] = func(rules *validate.StringBuilder[string]) {
rules.Use(validate.String[string]())
}
_ = configure
func (*StringBuilder[S]) When ¶
func (draft *StringBuilder[S]) When(condition ConditionBuilderFunc, configure ...func(*StringBuilder[S])) *StringBuilder[S]
When applies additional rules when the condition holds for the enclosing struct. The extra schema runs in place, in the order written, and sees defaults and exclusions like the rest of the chain.
Example:
type Value struct {
Name string
}
type Form struct {
Value string
Peer string
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StringBuilder[string]) {
rules.When(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
}, func(selected *validate.StringBuilder[string]) {
selected.Required()
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
type StringBuilderFunc ¶
type StringBuilderFunc[S ~string] = func(*StringBuilder[S])
StringBuilderFunc edits one temporary StringBuilder. Constructors invoke callbacks once, synchronously in order; a nil supplied callback panics.
Example:
var configure validate.StringBuilderFunc[string] = func(rules *validate.StringBuilder[string]) {
rules.Required()
}
_ = configure
type StringSchema ¶
type StringSchema[S ~string] struct { // contains filtered or unexported fields }
StringSchema validates strings and named string types. Create one with String. Lengths count runes, not bytes. Configure StringBuilder during construction; the published schema exposes execution and inspection only.
Example:
schema := validate.String(func(text *validate.StringBuilder[string]) {
text.Trim().Required()
})
value, err := schema.Parse(context.Background(), " Ada ")
if err != nil {
panic(err)
}
fmt.Println(value)
func String ¶
func String[S ~string](configure ...StringBuilderFunc[S]) StringSchema[S]
String publishes a schema for S, including named string types. Callbacks run once in order on one fresh draft; nil entries and callback panics propagate. Retained drafts cannot change the published rule containers.
Example:
schema := validate.String(func(rules *validate.StringBuilder[string]) {
rules.Trim()
rules.Required()
})
value, err := schema.Parse(context.Background(), " Ada ")
if err != nil {
panic(err)
}
fmt.Println(value)
Example (Named) ¶
ExampleString_named validates a named string type.
package main
import (
"context"
"fmt"
"arkoren.dev/foundation/validate"
)
func main() {
type color string
schema := validate.String(func(value *validate.StringBuilder[color]) {
value.OneOf("red", "green")
})
fmt.Println(schema.Validate(context.Background(), "red"))
fmt.Println(schema.Validate(context.Background(), "blue"))
}
Output: <nil> validation failed: (root): must be one of: red, green
func (StringSchema[S]) JSONSchema ¶
func (schema StringSchema[S]) JSONSchema() ([]byte, error)
JSONSchema renders this schema's supported JSON Schema constraints. Runtime-only rules remain enforced by Parse and Validate; invalid schema definitions or values that JSON cannot encode return an error. Definition errors wrap ErrInvalidSchema and return no document, including recorded Use errors and rules that need an enclosing struct. Export checks definitions but never executes Check or Normalize callbacks, including those attached to defaults. Default annotations retain the supplied value rather than a normalized runtime result.
Example:
schema := validate.String[string]()
document, err := schema.JSONSchema()
if err != nil {
panic(err)
}
_ = document
func (StringSchema[S]) Parse ¶
func (schema StringSchema[S]) Parse(ctx context.Context, v S) (S, error)
Parse checks the input and returns its normalized, defaulted result. It copies storage before applying schema changes and returns the zero value with Errors or a custom Check error when validation fails.
Example:
schema := validate.String[string]()
value, err := schema.Parse(context.Background(), "Ada")
if err != nil {
panic(err)
}
_ = value
func (StringSchema[S]) Validate ¶
func (schema StringSchema[S]) Validate(ctx context.Context, v S) error
Validate checks the input using the same preparation and rules as Parse, without returning the prepared value. It returns nil, Errors, or a custom Check error; caller-owned input is not modified.
Example:
schema := validate.String[string]()
if err := schema.Validate(context.Background(), "Ada"); err != nil {
panic(err)
}
type StructBuilder ¶
type StructBuilder[T any] struct { // contains filtered or unexported fields }
StructBuilder registers typed schemas for Go field names during Struct construction. Methods mutate this temporary draft, not published schemas. Retaining it is unnecessary; later registrations cannot change the result. A builder must not be mutated concurrently. The type parameter selects the exact validated struct type. Typed Field callbacks select a concrete child draft without reflection allocation.
Example:
type Person struct {
Name string
}
schema := validate.Struct[Person](func(object *validate.StructBuilder[Person]) {
object.Field("Name", func(name *validate.StringBuilder[string]) {
name.Required()
})
})
err := schema.Validate(context.Background(), Person{
Name: "Ada",
})
if err != nil {
panic(err)
}
func (*StructBuilder[T]) Bail ¶
func (draft *StructBuilder[T]) Bail() *StructBuilder[T]
Bail stops checking this value at its first failure. By default every failure is reported.
Example:
type Value struct {
Name string
}
type Form struct {
Value Value
Peer Value
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StructBuilder[Value]) {
rules.Bail()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StructBuilder[T]) Check ¶
func (draft *StructBuilder[T]) Check(fn func(context.Context, T) error) *StructBuilder[T]
Check adds a custom rule that runs only for present values. Return Fail (or At in a Struct check) to report a violation; any other error aborts validation and is returned to the caller unchanged.
Example:
type Value struct {
Name string
}
type Form struct {
Value Value
Peer Value
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StructBuilder[Value]) {
rules.Check(func(_ context.Context, value Value) error {
return nil
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
Example ¶
ExampleStructBuilder_Check reports a cross-field failure at a sibling field.
package main
import (
"context"
"errors"
"fmt"
"arkoren.dev/foundation/validate"
)
func main() {
type booking struct {
// Start is the first time slot.
Start int
// End must not precede Start.
End int
}
schema := validate.Struct(func(object *validate.StructBuilder[booking]) {
object.Check(func(_ context.Context, value booking) error {
if value.End < value.Start {
return validate.At("End", "booking.order", nil)
}
return nil
})
})
err := schema.Validate(context.Background(), booking{
Start: 5,
End: 1,
})
errs, ok := errors.AsType[validate.Errors](err)
if !ok {
fmt.Println(err)
return
}
for pointer, violations := range errs.All() {
fmt.Println(pointer, violations[0].Code)
}
}
Output: /End booking.order
func (*StructBuilder[T]) Default ¶
func (draft *StructBuilder[T]) Default(value T) *StructBuilder[T]
Default sets the value Parse uses when the prepared input is absent. Registered defaults are checked while a Struct is built; standalone defaults are checked by execution, not metadata export. Input normalizers run before default selection and do not run again on the selected default. Arbitrary default objects retain application ownership. Default cannot be combined with Required.
Example:
type Value struct {
Name string
}
type Form struct {
Value Value
Peer Value
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StructBuilder[Value]) {
rules.Default(Value{
Name: "Ada", })
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StructBuilder[T]) Describe ¶
func (draft *StructBuilder[T]) Describe(text string) *StructBuilder[T]
Describe sets the human-readable description that JSONSchema renders as "description". It does not affect validation. Use it for field and tool descriptions.
Example:
type Value struct {
Name string
}
type Form struct {
Value Value
Peer Value
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StructBuilder[Value]) {
rules.Describe("A display value")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StructBuilder[T]) EqField ¶
func (draft *StructBuilder[T]) EqField(field string) *StructBuilder[T]
EqField requires the value to equal the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value Value
Peer Value
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StructBuilder[Value]) {
rules.EqField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StructBuilder[T]) ExcludeIf ¶
func (draft *StructBuilder[T]) ExcludeIf(configure ...ConditionBuilderFunc) *StructBuilder[T]
ExcludeIf treats the value as absent, and clears it, when the conditions hold. Later ordinary value constraints skip absence, but later presence constraints still observe it and can report violations. Unconditional preparation may already have run before this rule is evaluated.
Example:
type Value struct {
Name string
}
type Form struct {
Value Value
Peer Value
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StructBuilder[Value]) {
rules.ExcludeIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StructBuilder[T]) Field ¶
func (object *StructBuilder[T]) Field[D any, P draftPointer[D]](name string, configure ...ChildBuilderFunc[P]) *StructBuilder[T]
Field publishes a concrete typed child draft for name and returns the same receiver. Callbacks run once, synchronously in order on one fresh child. It preserves invalid registrations for the enclosing construction report. Unregistered fields are not validated. The schema must validate the field's exact Go type; named types need their corresponding typed drafts. Invalid shared schemas, duplicate names, and invalid fields are reported together by Struct after all callbacks finish.
Example:
type Person struct {
Name string
}
schema := validate.Struct[Person](func(object *validate.StructBuilder[Person]) {
object.Field("Name", func(name *validate.StringBuilder[string]) {
name.Required()
})
})
err := schema.Validate(context.Background(), Person{
Name: "Ada",
})
if err != nil {
panic(err)
}
func (*StructBuilder[T]) NeField ¶
func (draft *StructBuilder[T]) NeField(field string) *StructBuilder[T]
NeField requires the value to differ from the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value Value
Peer Value
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StructBuilder[Value]) {
rules.NeField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StructBuilder[T]) Normalize ¶
func (draft *StructBuilder[T]) Normalize(fn func(T) T) *StructBuilder[T]
Normalize adds a custom normalizer. It runs before the presence check, Default and every rule, in the order written among the normalizers. It must return the value it is given or a new one, and must not modify its argument. Normalize cannot be used on Map key schemas.
Example:
type Value struct {
Name string
}
type Form struct {
Value Value
Peer Value
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StructBuilder[Value]) {
rules.Normalize(func(value Value) Value {
return value
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StructBuilder[T]) ProhibitedIf ¶
func (draft *StructBuilder[T]) ProhibitedIf(configure ...ConditionBuilderFunc) *StructBuilder[T]
ProhibitedIf fails when the value is present and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value Value
Peer Value
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StructBuilder[Value]) {
rules.ProhibitedIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StructBuilder[T]) ProhibitedUnless ¶
func (draft *StructBuilder[T]) ProhibitedUnless(configure ...ConditionBuilderFunc) *StructBuilder[T]
ProhibitedUnless fails when the value is present and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value Value
Peer Value
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StructBuilder[Value]) {
rules.ProhibitedUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StructBuilder[T]) Required ¶
func (draft *StructBuilder[T]) Required() *StructBuilder[T]
Required fails when the value is absent. Absent means zero, or nil for pointers, slices and maps. It cannot be combined with Default.
Example:
type Value struct {
Name string
}
type Form struct {
Value Value
Peer Value
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StructBuilder[Value]) {
rules.Required()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StructBuilder[T]) RequiredIf ¶
func (draft *StructBuilder[T]) RequiredIf(configure ...ConditionBuilderFunc) *StructBuilder[T]
RequiredIf fails when the value is absent and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value Value
Peer Value
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StructBuilder[Value]) {
rules.RequiredIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StructBuilder[T]) RequiredUnless ¶
func (draft *StructBuilder[T]) RequiredUnless(configure ...ConditionBuilderFunc) *StructBuilder[T]
RequiredUnless fails when the value is absent and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value Value
Peer Value
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StructBuilder[Value]) {
rules.RequiredUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StructBuilder[T]) RequiredWith ¶
func (draft *StructBuilder[T]) RequiredWith(fields ...string) *StructBuilder[T]
RequiredWith fails when the value is absent and any of the sibling fields is present.
Example:
type Value struct {
Name string
}
type Form struct {
Value Value
Peer Value
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StructBuilder[Value]) {
rules.RequiredWith("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StructBuilder[T]) RequiredWithAll ¶
func (draft *StructBuilder[T]) RequiredWithAll(fields ...string) *StructBuilder[T]
RequiredWithAll fails when the value is absent and all of the sibling fields are present.
Example:
type Value struct {
Name string
}
type Form struct {
Value Value
Peer Value
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StructBuilder[Value]) {
rules.RequiredWithAll("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StructBuilder[T]) RequiredWithout ¶
func (draft *StructBuilder[T]) RequiredWithout(fields ...string) *StructBuilder[T]
RequiredWithout fails when the value is absent and any of the sibling fields is absent.
Example:
type Value struct {
Name string
}
type Form struct {
Value Value
Peer Value
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StructBuilder[Value]) {
rules.RequiredWithout("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*StructBuilder[T]) Use ¶
func (object *StructBuilder[T]) Use(schema Schema[T]) *StructBuilder[T]
Use adds a published schema's object-wide rules and registered fields. Later local Field declarations remain checked for duplicate registrations. The source must be StructSchema[T] (value or nonnil pointer), or InferSchema[T] for type-only documentation. Other roles with the same T are rejected instead of losing their validation plan. A typed nil pointer wraps ErrInvalidSchema.
Example:
type Person struct {
Name string
}
shared := validate.Struct[Person]()
schema := validate.Struct(func(object *validate.StructBuilder[Person]) {
object.Use(shared)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*StructBuilder[T]) When ¶
func (draft *StructBuilder[T]) When(condition ConditionBuilderFunc, configure ...func(*StructBuilder[T])) *StructBuilder[T]
When applies additional rules when the condition holds for the enclosing struct. The extra schema runs in place, in the order written, and sees defaults and exclusions like the rest of the chain.
Example:
type Value struct {
Name string
}
type Form struct {
Value Value
Peer Value
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.StructBuilder[Value]) {
rules.When(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
}, func(selected *validate.StructBuilder[Value]) {
selected.Required()
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
type StructBuilderFunc ¶
type StructBuilderFunc[T any] = func(*StructBuilder[T])
StructBuilderFunc configures one temporary struct draft for T. Callbacks run once in order; nil supplied callbacks panic and publication detaches owned state.
Example:
type Person struct {
Name string
}
var fields validate.StructBuilderFunc[Person] = func(object *validate.StructBuilder[Person]) {
object.Field("Name", func(name *validate.StringBuilder[string]) {
name.Required()
})
}
schema := validate.Struct(fields)
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
type StructSchema ¶
type StructSchema[T any] struct { // contains filtered or unexported fields }
StructSchema validates a struct. Create one with Struct.
Errors are keyed by the JSON Pointer of each field, using the names the encoding/json/v2 package gives it. An object always checks its fields; wrap it in Ptr to make the whole object optional. A zero StructSchema is uninitialized: JSONSchema returns an error wrapping ErrInvalidSchema, and Parse and Validate panic with an error wrapping that sentinel through compilation. Use Struct[T]() for a valid schema without registered fields.
Example:
schema := validate.Struct[struct {
Name string
}]()
value, err := schema.Parse(context.Background(), struct {
Name string
}{
Name: "Ada",
})
if err != nil {
panic(err)
}
fmt.Println(value.Name)
func Struct ¶
func Struct[T any](define ...StructBuilderFunc[T]) StructSchema[T]
Struct returns a schema for the struct type T. Field registrations name Go fields of T, and every schema must validate exactly the type of its field; there is no conversion, so a named string field needs StringBuilder instantiated with that named string type.
Callbacks run once, synchronously, in argument order on the same builder. Zero callbacks, including an expanded nil or empty slice, register no fields; T must still be a supported struct. Supplied nil callbacks and callback panics propagate directly. Registrations are detached before publication. Compiled fields execute in struct order, not registration order.
Struct panics with an error wrapping ErrInvalidSchema when registration is wrong. The message lists every problem: unknown names with suggestions, unexported or JSON-excluded fields, type mismatches, bad condition fields and values, Required combined with Default, and defaults that fail their own schema. Invalid string lengths, numeric factors and non-finite numeric bounds are recorded without stopping callbacks and included in the same report. Diagnostics are sorted by Go name, preserving registration order for ties.
Example:
type Signup struct {
Email string
}
schema := validate.Struct[Signup](func(object *validate.StructBuilder[Signup]) {
object.Field("Email", func(email *validate.StringBuilder[string]) {
email.Trim().Email().Required()
})
})
value, err := schema.Parse(context.Background(), Signup{
Email: " ada@example.com ",
})
if err != nil {
panic(err)
}
fmt.Println(value.Email)
Example ¶
ExampleStruct validates a struct and prints the violations by JSON Pointer.
package main
import (
"context"
"errors"
"fmt"
"arkoren.dev/foundation/validate"
)
// signup is the registration input shared by the public examples.
type signup struct {
Email string `json:"email"`
Password string `json:"password"`
Confirm string `json:"confirm"`
Plan string `json:"plan"`
Terms bool `json:"terms"`
}
// registration validates signups and defaults the membership plan.
var registration = validate.Struct(func(object *validate.StructBuilder[signup]) {
object.Field("Email", func(value *validate.StringBuilder[string]) {
value.Required()
value.Email()
})
object.Field("Password", func(value *validate.StringBuilder[string]) {
value.Required()
value.Min(12)
})
object.Field("Confirm", func(value *validate.StringBuilder[string]) {
value.EqField("Password")
})
object.Field("Plan", func(value *validate.StringBuilder[string]) {
value.OneOf("free", "pro")
value.Default("free")
})
object.Field("Terms", func(value *validate.BoolBuilder[bool]) {
value.Accepted()
})
})
func main() {
err := registration.Validate(context.Background(), signup{
Email: "not-an-email",
Password: "short",
Confirm: "different",
})
errs, ok := errors.AsType[validate.Errors](err)
if !ok {
fmt.Println(err)
return
}
for pointer, violations := range errs.All() {
for _, violation := range violations {
fmt.Printf("%s %s: %s\n", pointer, violation.Code, violation.Message)
}
}
}
Output: /confirm eq_field: must equal password /email string.email: must be a valid email address /password string.min: must be at least 12 characters /terms bool.accepted: must be accepted
Example (Conditions) ¶
ExampleStruct_conditions requires a VAT identifier for company contacts, while leaving it optional for people.
package main
import (
"context"
"fmt"
"arkoren.dev/foundation/validate"
)
func main() {
type contact struct {
// Kind distinguishes a person from a company.
Kind string
// VAT is the company's tax identifier.
VAT string
}
schema := validate.Struct(func(object *validate.StructBuilder[contact]) {
object.Field("Kind", func(value *validate.StringBuilder[string]) {
value.OneOf("person", "company")
})
object.Field("VAT", func(value *validate.StringBuilder[string]) {
value.RequiredIf(func(condition *validate.ConditionBuilder) {
condition.Eq("Kind", "company")
})
})
})
fmt.Println(schema.Validate(context.Background(), contact{
Kind: "company",
}))
}
Output: validation failed: /VAT: is required when Kind is company
Example (Nested) ¶
ExampleStruct_nested composes a value struct and an optional pointer schema.
package main
import (
"context"
"errors"
"fmt"
"arkoren.dev/foundation/validate"
)
func main() {
type Address struct {
// City is required when an address is present.
City string `json:"city"`
}
type User struct {
// Address is the user's primary address.
Address Address `json:"address"`
// Billing is an optional billing address.
Billing *Address `json:"billing"`
}
address := validate.Struct(func(object *validate.StructBuilder[Address]) {
object.Field("City", func(value *validate.StringBuilder[string]) {
value.Trim()
value.Required()
})
})
user := validate.Struct(func(object *validate.StructBuilder[User]) {
object.Field("Address", func(object *validate.StructBuilder[Address]) {
object.Use(address)
})
object.Field("Billing", func(pointer *validate.PtrBuilder[Address]) {
pointer.Value(func(object *validate.StructBuilder[Address]) {
object.Use(address)
})
})
})
err := user.Validate(context.Background(), User{})
failures, ok := errors.AsType[validate.Errors](err)
if !ok {
fmt.Println(err)
return
}
for pointer, violations := range failures.All() {
fmt.Println(pointer, violations[0].Code)
}
fmt.Println(user.Validate(context.Background(), User{
Address: Address{
City: "Paris",
},
}))
}
Output: /address/city required <nil>
func (StructSchema[T]) JSONSchema ¶
func (schema StructSchema[T]) JSONSchema() ([]byte, error)
JSONSchema renders this schema's supported JSON Schema constraints. Runtime-only rules remain enforced by Parse and Validate; invalid schema definitions or values that JSON cannot encode return an error. A zero StructSchema returns an error wrapping ErrInvalidSchema. Export never executes validation callbacks or rechecks field defaults verified by Struct.
Example:
schema := validate.Struct[struct{}]()
document, err := schema.JSONSchema()
if err != nil {
panic(err)
}
_ = document
func (StructSchema[T]) Parse ¶
func (schema StructSchema[T]) Parse(ctx context.Context, v T) (T, error)
Parse checks the input and returns its normalized, defaulted result. It copies storage before applying schema changes and returns the zero value with Errors or a custom Check error when validation fails.
Example:
schema := validate.Struct[struct{}]()
value, err := schema.Parse(context.Background(), struct{}{})
if err != nil {
panic(err)
}
_ = value
Example ¶
ExampleStructSchema_Parse applies defaults and returns a copy.
package main
import (
"context"
"fmt"
"arkoren.dev/foundation/validate"
)
// signup is the registration input shared by the public examples.
type signup struct {
Email string `json:"email"`
Password string `json:"password"`
Confirm string `json:"confirm"`
Plan string `json:"plan"`
Terms bool `json:"terms"`
}
// registration validates signups and defaults the membership plan.
var registration = validate.Struct(func(object *validate.StructBuilder[signup]) {
object.Field("Email", func(value *validate.StringBuilder[string]) {
value.Required()
value.Email()
})
object.Field("Password", func(value *validate.StringBuilder[string]) {
value.Required()
value.Min(12)
})
object.Field("Confirm", func(value *validate.StringBuilder[string]) {
value.EqField("Password")
})
object.Field("Plan", func(value *validate.StringBuilder[string]) {
value.OneOf("free", "pro")
value.Default("free")
})
object.Field("Terms", func(value *validate.BoolBuilder[bool]) {
value.Accepted()
})
})
func main() {
input := signup{
Email: "ada@example.com",
Password: "correct horse battery",
Confirm: "correct horse battery",
Terms: true,
}
parsed, err := registration.Parse(context.Background(), input)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(err, parsed.Plan, input.Plan == "")
}
Output: <nil> free true
func (StructSchema[T]) Validate ¶
func (schema StructSchema[T]) Validate(ctx context.Context, v T) error
Validate checks the input using the same preparation and rules as Parse, without returning the prepared value. It returns nil, Errors, or a custom Check error; caller-owned input is not modified.
Example:
schema := validate.Struct[struct{}]()
if err := schema.Validate(context.Background(), struct{}{}); err != nil {
panic(err)
}
type TextBuilder ¶
type TextBuilder[T any] struct { // contains filtered or unexported fields }
TextBuilder configures a detached TextSchema during construction. Settings return the same draft. Retaining a draft cannot change a schema; concurrent mutation of a draft is not supported.
Example:
var configure validate.TextBuilderFunc[validate.Duration] = func(rules *validate.TextBuilder[validate.Duration]) {
rules.Required()
}
_ = configure
func (*TextBuilder[T]) Bail ¶
func (draft *TextBuilder[T]) Bail() *TextBuilder[T]
Bail stops checking this value at its first failure. By default every failure is reported.
Example:
type Value struct {
Name string
}
type Form struct {
Value validate.Duration
Peer validate.Duration
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TextBuilder[validate.Duration]) {
rules.Bail()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TextBuilder[T]) Check ¶
func (draft *TextBuilder[T]) Check(fn func(context.Context, T) error) *TextBuilder[T]
Check adds a custom rule that runs only for present values. Return Fail (or At in a Struct check) to report a violation; any other error aborts validation and is returned to the caller unchanged.
Example:
type Value struct {
Name string
}
type Form struct {
Value validate.Duration
Peer validate.Duration
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TextBuilder[validate.Duration]) {
rules.Check(func(_ context.Context, value validate.Duration) error {
return nil
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TextBuilder[T]) Default ¶
func (draft *TextBuilder[T]) Default(value T) *TextBuilder[T]
Default sets the value Parse uses when the prepared input is absent. Registered defaults are checked while a Struct is built; standalone defaults are checked by execution, not metadata export. Input normalizers run before default selection and do not run again on the selected default. Arbitrary default objects retain application ownership. Default cannot be combined with Required.
Example:
type Value struct {
Name string
}
type Form struct {
Value validate.Duration
Peer validate.Duration
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TextBuilder[validate.Duration]) {
rules.Default(validate.Duration(time.Second))
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TextBuilder[T]) Describe ¶
func (draft *TextBuilder[T]) Describe(text string) *TextBuilder[T]
Describe sets the human-readable description that JSONSchema renders as "description". It does not affect validation. Use it for field and tool descriptions.
Example:
type Value struct {
Name string
}
type Form struct {
Value validate.Duration
Peer validate.Duration
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TextBuilder[validate.Duration]) {
rules.Describe("A display value")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TextBuilder[T]) EqField ¶
func (draft *TextBuilder[T]) EqField(field string) *TextBuilder[T]
EqField requires the value to equal the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value validate.Duration
Peer validate.Duration
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TextBuilder[validate.Duration]) {
rules.EqField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TextBuilder[T]) ExcludeIf ¶
func (draft *TextBuilder[T]) ExcludeIf(configure ...ConditionBuilderFunc) *TextBuilder[T]
ExcludeIf treats the value as absent, and clears it, when the conditions hold. Later ordinary value constraints skip absence, but later presence constraints still observe it and can report violations. Unconditional preparation may already have run before this rule is evaluated.
Example:
type Value struct {
Name string
}
type Form struct {
Value validate.Duration
Peer validate.Duration
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TextBuilder[validate.Duration]) {
rules.ExcludeIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TextBuilder[T]) NeField ¶
func (draft *TextBuilder[T]) NeField(field string) *TextBuilder[T]
NeField requires the value to differ from the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value validate.Duration
Peer validate.Duration
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TextBuilder[validate.Duration]) {
rules.NeField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TextBuilder[T]) Normalize ¶
func (draft *TextBuilder[T]) Normalize(fn func(T) T) *TextBuilder[T]
Normalize adds a custom normalizer. It runs before the presence check, Default and every rule, in the order written among the normalizers. It must return the value it is given or a new one, and must not modify its argument. Normalize cannot be used on Map key schemas.
Example:
type Value struct {
Name string
}
type Form struct {
Value validate.Duration
Peer validate.Duration
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TextBuilder[validate.Duration]) {
rules.Normalize(func(value validate.Duration) validate.Duration {
return value
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TextBuilder[T]) ProhibitedIf ¶
func (draft *TextBuilder[T]) ProhibitedIf(configure ...ConditionBuilderFunc) *TextBuilder[T]
ProhibitedIf fails when the value is present and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value validate.Duration
Peer validate.Duration
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TextBuilder[validate.Duration]) {
rules.ProhibitedIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TextBuilder[T]) ProhibitedUnless ¶
func (draft *TextBuilder[T]) ProhibitedUnless(configure ...ConditionBuilderFunc) *TextBuilder[T]
ProhibitedUnless fails when the value is present and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value validate.Duration
Peer validate.Duration
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TextBuilder[validate.Duration]) {
rules.ProhibitedUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TextBuilder[T]) Required ¶
func (draft *TextBuilder[T]) Required() *TextBuilder[T]
Required fails when the value is absent. Absent means zero, or nil for pointers, slices and maps. It cannot be combined with Default.
Example:
type Value struct {
Name string
}
type Form struct {
Value validate.Duration
Peer validate.Duration
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TextBuilder[validate.Duration]) {
rules.Required()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TextBuilder[T]) RequiredIf ¶
func (draft *TextBuilder[T]) RequiredIf(configure ...ConditionBuilderFunc) *TextBuilder[T]
RequiredIf fails when the value is absent and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value validate.Duration
Peer validate.Duration
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TextBuilder[validate.Duration]) {
rules.RequiredIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TextBuilder[T]) RequiredUnless ¶
func (draft *TextBuilder[T]) RequiredUnless(configure ...ConditionBuilderFunc) *TextBuilder[T]
RequiredUnless fails when the value is absent and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value validate.Duration
Peer validate.Duration
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TextBuilder[validate.Duration]) {
rules.RequiredUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TextBuilder[T]) RequiredWith ¶
func (draft *TextBuilder[T]) RequiredWith(fields ...string) *TextBuilder[T]
RequiredWith fails when the value is absent and any of the sibling fields is present.
Example:
type Value struct {
Name string
}
type Form struct {
Value validate.Duration
Peer validate.Duration
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TextBuilder[validate.Duration]) {
rules.RequiredWith("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TextBuilder[T]) RequiredWithAll ¶
func (draft *TextBuilder[T]) RequiredWithAll(fields ...string) *TextBuilder[T]
RequiredWithAll fails when the value is absent and all of the sibling fields are present.
Example:
type Value struct {
Name string
}
type Form struct {
Value validate.Duration
Peer validate.Duration
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TextBuilder[validate.Duration]) {
rules.RequiredWithAll("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TextBuilder[T]) RequiredWithout ¶
func (draft *TextBuilder[T]) RequiredWithout(fields ...string) *TextBuilder[T]
RequiredWithout fails when the value is absent and any of the sibling fields is absent.
Example:
type Value struct {
Name string
}
type Form struct {
Value validate.Duration
Peer validate.Duration
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TextBuilder[validate.Duration]) {
rules.RequiredWithout("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TextBuilder[T]) Use ¶
func (draft *TextBuilder[T]) Use(schema Schema[T]) *TextBuilder[T]
Use adds rules from the same published schema role, as a value or nonnil pointer, before subsequent local settings. InferSchema contributes type-only documentation, not validation or missing child definitions. FromJSONSchema provides a separate decoded-JSON API, not a Schema value accepted here. Other schema roles are rejected even when their value type matches, because importing only their base could lose child rules. Schema-level rules accumulate. Overlapping child definitions are construction errors, and later local child callbacks cannot replace an imported child. Ptr permits an unconstrained scalar adapter to yield to a shared pointee. The source remains immutable. Typed nil pointers wrap ErrInvalidSchema.
Example:
var configure validate.TextBuilderFunc[validate.Duration] = func(rules *validate.TextBuilder[validate.Duration]) {
rules.Use(validate.Text[validate.Duration]())
}
_ = configure
func (*TextBuilder[T]) When ¶
func (draft *TextBuilder[T]) When(condition ConditionBuilderFunc, configure ...func(*TextBuilder[T])) *TextBuilder[T]
When applies additional rules when the condition holds for the enclosing struct. The extra schema runs in place, in the order written, and sees defaults and exclusions like the rest of the chain.
Example:
type Value struct {
Name string
}
type Form struct {
Value validate.Duration
Peer validate.Duration
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TextBuilder[validate.Duration]) {
rules.When(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
}, func(selected *validate.TextBuilder[validate.Duration]) {
selected.Required()
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
type TextBuilderFunc ¶
type TextBuilderFunc[T any] = func(*TextBuilder[T])
TextBuilderFunc edits one temporary TextBuilder. Constructors invoke callbacks once, synchronously in order; a nil supplied callback panics.
Example:
var configure validate.TextBuilderFunc[validate.Duration] = func(rules *validate.TextBuilder[validate.Duration]) {
rules.Required()
}
_ = configure
type TextSchema ¶
type TextSchema[T any] struct { // contains filtered or unexported fields }
TextSchema validates values of a type that encodes as a JSON string through encoding.TextMarshaler and encoding.TextUnmarshaler, such as Duration, net/netip.Addr or a UUID type. Create one with Text. A zero value of the type is absent, like for the other leaf schemas.
The schema checks no format by itself, because the type has already parsed its text; add rules with Check. It exists so that such fields can be registered with StructBuilder.Field and render as a string in JSON Schema.
Example:
schema := validate.Text[validate.Duration]()
value, err := schema.Parse(context.Background(), validate.Duration(time.Second))
if err != nil {
panic(err)
}
fmt.Println(value.Std())
func Text ¶
func Text[T any, PT interface { *T encoding.TextMarshaler encoding.TextUnmarshaler }](configure ...TextBuilderFunc[T]) TextSchema[T]
Text returns a schema for T, a type whose pointer implements encoding.TextMarshaler and encoding.TextUnmarshaler. The pointer constraint is how Go expresses that UnmarshalText normally has a pointer receiver while the field holds a T: write Text[Duration](), the second type argument is inferred.
The JSON Schema is {"type":"string"}, plus "format" when T or *T has a JSONSchemaFormat() string method. That method is called once, on a zero value, so it must return a constant.
Example:
type Job struct {
Timeout validate.Duration
}
var job = validate.Struct[Job](func(object *validate.StructBuilder[Job]) {
object.Field("Timeout", func(timeout *validate.TextBuilder[validate.Duration]) {
timeout.Describe("Per attempt")
})
})
err := job.Validate(context.Background(), Job{
Timeout: validate.Duration(time.Second),
})
if err != nil {
panic(err)
}
func (TextSchema[T]) JSONSchema ¶
func (schema TextSchema[T]) JSONSchema() ([]byte, error)
JSONSchema renders this schema's supported JSON Schema constraints. Runtime-only rules remain enforced by Parse and Validate; invalid schema definitions or values that JSON cannot encode return an error. As with StringSchema.JSONSchema, definition checks never execute validation callbacks; recorded construction errors wrap ErrInvalidSchema.
Example:
schema := validate.Text[validate.Duration]()
document, err := schema.JSONSchema()
if err != nil {
panic(err)
}
_ = document
func (TextSchema[T]) Parse ¶
func (schema TextSchema[T]) Parse(ctx context.Context, v T) (T, error)
Parse checks the input and returns its normalized, defaulted result. It copies storage before applying schema changes and returns the zero value with Errors or a custom Check error when validation fails.
Example:
schema := validate.Text[validate.Duration]()
value, err := schema.Parse(context.Background(), validate.Duration(time.Second))
if err != nil {
panic(err)
}
_ = value
func (TextSchema[T]) Validate ¶
func (schema TextSchema[T]) Validate(ctx context.Context, v T) error
Validate checks the input using the same preparation and rules as Parse, without returning the prepared value. It returns nil, Errors, or a custom Check error; caller-owned input is not modified.
Example:
schema := validate.Text[validate.Duration]()
if err := schema.Validate(context.Background(), validate.Duration(time.Second)); err != nil {
panic(err)
}
type TimeBuilder ¶
type TimeBuilder struct {
// contains filtered or unexported fields
}
TimeBuilder configures a detached TimeSchema during construction. Settings return the same draft. Retaining a draft cannot change a schema; concurrent mutation of a draft is not supported.
Example:
var configure validate.TimeBuilderFunc = func(rules *validate.TimeBuilder) {
rules.Required()
}
_ = configure
func (*TimeBuilder) After ¶
func (moment *TimeBuilder) After(limit time.Time) *TimeBuilder
After requires a time after limit.
Example:
schema := validate.Time(func(moment *validate.TimeBuilder) {
moment.After(time.Unix(0, 0))
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*TimeBuilder) AfterField ¶
func (moment *TimeBuilder) AfterField(field string) *TimeBuilder
AfterField requires a time after the sibling time field.
Example:
type Interval struct {
Start, End time.Time
}
schema := validate.Struct(func(object *validate.StructBuilder[Interval]) {
object.Field("End", func(moment *validate.TimeBuilder) {
moment.AfterField("Start")
})
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*TimeBuilder) Bail ¶
func (draft *TimeBuilder) Bail() *TimeBuilder
Bail stops checking this value at its first failure. By default every failure is reported.
Example:
type Value struct {
Name string
}
type Form struct {
Value time.Time
Peer time.Time
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TimeBuilder) {
rules.Bail()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TimeBuilder) Before ¶
func (moment *TimeBuilder) Before(limit time.Time) *TimeBuilder
Before requires a time before limit.
Example:
schema := validate.Time(func(moment *validate.TimeBuilder) {
moment.Before(time.Date(2030, 1, 1, 0, 0, 0, 0, time.UTC))
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*TimeBuilder) BeforeField ¶
func (moment *TimeBuilder) BeforeField(field string) *TimeBuilder
BeforeField requires a time before the sibling time field.
Example:
type Interval struct {
Start, End time.Time
}
schema := validate.Struct(func(object *validate.StructBuilder[Interval]) {
object.Field("Start", func(moment *validate.TimeBuilder) {
moment.BeforeField("End")
})
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*TimeBuilder) Between ¶
func (moment *TimeBuilder) Between(low, high time.Time) *TimeBuilder
Between requires a time from low to high, inclusive.
Example:
schema := validate.Time(func(moment *validate.TimeBuilder) {
moment.Between(time.Unix(0, 0), time.Date(2030, 1, 1, 0, 0, 0, 0, time.UTC))
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*TimeBuilder) Check ¶
func (draft *TimeBuilder) Check(fn func(context.Context, time.Time) error) *TimeBuilder
Check adds a custom rule that runs only for present values. Return Fail (or At in a Struct check) to report a violation; any other error aborts validation and is returned to the caller unchanged.
Example:
type Value struct {
Name string
}
type Form struct {
Value time.Time
Peer time.Time
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TimeBuilder) {
rules.Check(func(_ context.Context, value time.Time) error {
return nil
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TimeBuilder) Default ¶
func (draft *TimeBuilder) Default(value time.Time) *TimeBuilder
Default sets the value Parse uses when the prepared input is absent. Registered defaults are checked while a Struct is built; standalone defaults are checked by execution, not metadata export. Input normalizers run before default selection and do not run again on the selected default. Arbitrary default objects retain application ownership. Default cannot be combined with Required.
Example:
type Value struct {
Name string
}
type Form struct {
Value time.Time
Peer time.Time
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TimeBuilder) {
rules.Default(time.Date(2026,1,1,0,0,0,0,time.UTC))
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TimeBuilder) Describe ¶
func (draft *TimeBuilder) Describe(text string) *TimeBuilder
Describe sets the human-readable description that JSONSchema renders as "description". It does not affect validation. Use it for field and tool descriptions.
Example:
type Value struct {
Name string
}
type Form struct {
Value time.Time
Peer time.Time
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TimeBuilder) {
rules.Describe("A display value")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TimeBuilder) EqField ¶
func (draft *TimeBuilder) EqField(field string) *TimeBuilder
EqField requires the value to equal the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value time.Time
Peer time.Time
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TimeBuilder) {
rules.EqField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TimeBuilder) ExcludeIf ¶
func (draft *TimeBuilder) ExcludeIf(configure ...ConditionBuilderFunc) *TimeBuilder
ExcludeIf treats the value as absent, and clears it, when the conditions hold. Later ordinary value constraints skip absence, but later presence constraints still observe it and can report violations. Unconditional preparation may already have run before this rule is evaluated.
Example:
type Value struct {
Name string
}
type Form struct {
Value time.Time
Peer time.Time
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TimeBuilder) {
rules.ExcludeIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TimeBuilder) Future ¶
func (moment *TimeBuilder) Future() *TimeBuilder
Future requires a time after the current time.
Example:
schema := validate.Time(func(moment *validate.TimeBuilder) {
moment.Future()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*TimeBuilder) NeField ¶
func (draft *TimeBuilder) NeField(field string) *TimeBuilder
NeField requires the value to differ from the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value time.Time
Peer time.Time
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TimeBuilder) {
rules.NeField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TimeBuilder) Normalize ¶
func (draft *TimeBuilder) Normalize(fn func(time.Time) time.Time) *TimeBuilder
Normalize adds a custom normalizer. It runs before the presence check, Default and every rule, in the order written among the normalizers. It must return the value it is given or a new one, and must not modify its argument. Normalize cannot be used on Map key schemas.
Example:
type Value struct {
Name string
}
type Form struct {
Value time.Time
Peer time.Time
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TimeBuilder) {
rules.Normalize(func(value time.Time) time.Time {
return value
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TimeBuilder) Past ¶
func (moment *TimeBuilder) Past() *TimeBuilder
Past requires a time before the current time.
Example:
schema := validate.Time(func(moment *validate.TimeBuilder) {
moment.Past()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*TimeBuilder) ProhibitedIf ¶
func (draft *TimeBuilder) ProhibitedIf(configure ...ConditionBuilderFunc) *TimeBuilder
ProhibitedIf fails when the value is present and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value time.Time
Peer time.Time
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TimeBuilder) {
rules.ProhibitedIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TimeBuilder) ProhibitedUnless ¶
func (draft *TimeBuilder) ProhibitedUnless(configure ...ConditionBuilderFunc) *TimeBuilder
ProhibitedUnless fails when the value is present and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value time.Time
Peer time.Time
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TimeBuilder) {
rules.ProhibitedUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TimeBuilder) Required ¶
func (draft *TimeBuilder) Required() *TimeBuilder
Required fails when the value is absent. Absent means zero, or nil for pointers, slices and maps. It cannot be combined with Default.
Example:
type Value struct {
Name string
}
type Form struct {
Value time.Time
Peer time.Time
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TimeBuilder) {
rules.Required()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TimeBuilder) RequiredIf ¶
func (draft *TimeBuilder) RequiredIf(configure ...ConditionBuilderFunc) *TimeBuilder
RequiredIf fails when the value is absent and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value time.Time
Peer time.Time
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TimeBuilder) {
rules.RequiredIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TimeBuilder) RequiredUnless ¶
func (draft *TimeBuilder) RequiredUnless(configure ...ConditionBuilderFunc) *TimeBuilder
RequiredUnless fails when the value is absent and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value time.Time
Peer time.Time
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TimeBuilder) {
rules.RequiredUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TimeBuilder) RequiredWith ¶
func (draft *TimeBuilder) RequiredWith(fields ...string) *TimeBuilder
RequiredWith fails when the value is absent and any of the sibling fields is present.
Example:
type Value struct {
Name string
}
type Form struct {
Value time.Time
Peer time.Time
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TimeBuilder) {
rules.RequiredWith("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TimeBuilder) RequiredWithAll ¶
func (draft *TimeBuilder) RequiredWithAll(fields ...string) *TimeBuilder
RequiredWithAll fails when the value is absent and all of the sibling fields are present.
Example:
type Value struct {
Name string
}
type Form struct {
Value time.Time
Peer time.Time
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TimeBuilder) {
rules.RequiredWithAll("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TimeBuilder) RequiredWithout ¶
func (draft *TimeBuilder) RequiredWithout(fields ...string) *TimeBuilder
RequiredWithout fails when the value is absent and any of the sibling fields is absent.
Example:
type Value struct {
Name string
}
type Form struct {
Value time.Time
Peer time.Time
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TimeBuilder) {
rules.RequiredWithout("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*TimeBuilder) UTC ¶
func (moment *TimeBuilder) UTC() *TimeBuilder
UTC converts the time to UTC. It is a normalizer: it runs before presence, Default and every rule, in the order written. The zero time stays zero.
Example:
schema := validate.Time(func(moment *validate.TimeBuilder) {
moment.UTC()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*TimeBuilder) Use ¶
func (draft *TimeBuilder) Use(schema Schema[time.Time]) *TimeBuilder
Use adds rules from the same published schema role, as a value or nonnil pointer, before subsequent local settings. InferSchema contributes type-only documentation, not validation or missing child definitions. FromJSONSchema provides a separate decoded-JSON API, not a Schema value accepted here. Other schema roles are rejected even when their value type matches, because importing only their base could lose child rules. Schema-level rules accumulate. Overlapping child definitions are construction errors, and later local child callbacks cannot replace an imported child. Ptr permits an unconstrained scalar adapter to yield to a shared pointee. The source remains immutable. Typed nil pointers wrap ErrInvalidSchema.
Example:
var configure validate.TimeBuilderFunc = func(rules *validate.TimeBuilder) {
rules.Use(validate.Time())
}
_ = configure
func (*TimeBuilder) When ¶
func (draft *TimeBuilder) When(condition ConditionBuilderFunc, configure ...func(*TimeBuilder)) *TimeBuilder
When applies additional rules when the condition holds for the enclosing struct. The extra schema runs in place, in the order written, and sees defaults and exclusions like the rest of the chain.
Example:
type Value struct {
Name string
}
type Form struct {
Value time.Time
Peer time.Time
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.TimeBuilder) {
rules.When(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
}, func(selected *validate.TimeBuilder) {
selected.Required()
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
type TimeBuilderFunc ¶
type TimeBuilderFunc = func(*TimeBuilder)
TimeBuilderFunc edits one temporary TimeBuilder. Constructors invoke callbacks once, synchronously in order; a nil supplied callback panics.
Example:
var configure validate.TimeBuilderFunc = func(rules *validate.TimeBuilder) {
rules.Required()
}
_ = configure
type TimeSchema ¶
type TimeSchema struct {
// contains filtered or unexported fields
}
TimeSchema validates time.Time values. Create one with Time. The zero time counts as absent. Future and Past read the clock from the context, see NewClockContext.
Example:
schema := validate.Time(func(moment *validate.TimeBuilder) {
moment.UTC()
})
value, err := schema.Parse(context.Background(), time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC))
if err != nil {
panic(err)
}
fmt.Println(value.Location())
func Time ¶
func Time(configure ...TimeBuilderFunc) TimeSchema
Time publishes a schema for time.Time. Callbacks run once in order on one fresh draft and retained drafts cannot change the immutable result.
Example:
schema := validate.Time(func(moment *validate.TimeBuilder) {
moment.UTC()
})
value, err := schema.Parse(context.Background(), time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC))
if err != nil {
panic(err)
}
fmt.Println(value.Location())
func (TimeSchema) JSONSchema ¶
func (schema TimeSchema) JSONSchema() ([]byte, error)
JSONSchema renders this schema's supported JSON Schema constraints. Runtime-only rules remain enforced by Parse and Validate; invalid schema definitions or values that JSON cannot encode return an error. As with StringSchema.JSONSchema, definition checks never execute validation callbacks; recorded construction errors wrap ErrInvalidSchema.
Example:
schema := validate.Time()
document, err := schema.JSONSchema()
if err != nil {
panic(err)
}
_ = document
func (TimeSchema) Parse ¶
Parse checks the input and returns its normalized, defaulted result. It copies storage before applying schema changes and returns the zero value with Errors or a custom Check error when validation fails.
Example:
schema := validate.Time()
value, err := schema.Parse(context.Background(), time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC))
if err != nil {
panic(err)
}
_ = value
func (TimeSchema) Validate ¶
Validate checks the input using the same preparation and rules as Parse, without returning the prepared value. It returns nil, Errors, or a custom Check error; caller-owned input is not modified.
Example:
schema := validate.Time()
if err := schema.Validate(context.Background(), time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)); err != nil {
panic(err)
}
type UintBuilder ¶
type UintBuilder[N unsigned] struct {
// contains filtered or unexported fields
}
UintBuilder configures a detached UintSchema during construction. Settings return the same draft. Retaining a draft cannot change a schema; concurrent mutation of a draft is not supported.
Example:
var configure validate.UintBuilderFunc[uint] = func(rules *validate.UintBuilder[uint]) {
rules.Required()
}
_ = configure
func (*UintBuilder[N]) Bail ¶
func (draft *UintBuilder[N]) Bail() *UintBuilder[N]
Bail stops checking this value at its first failure. By default every failure is reported.
Example:
type Value struct {
Name string
}
type Form struct {
Value uint
Peer uint
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.UintBuilder[uint]) {
rules.Bail()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*UintBuilder[N]) Between ¶
func (number *UintBuilder[N]) Between(low, high N) *UintBuilder[N]
Between requires a value from low to high, inclusive.
Example:
schema := validate.Uint(func(number *validate.UintBuilder[uint]) {
number.Between(1, 100)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*UintBuilder[N]) Check ¶
func (draft *UintBuilder[N]) Check(fn func(context.Context, N) error) *UintBuilder[N]
Check adds a custom rule that runs only for present values. Return Fail (or At in a Struct check) to report a violation; any other error aborts validation and is returned to the caller unchanged.
Example:
type Value struct {
Name string
}
type Form struct {
Value uint
Peer uint
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.UintBuilder[uint]) {
rules.Check(func(_ context.Context, value uint) error {
return nil
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*UintBuilder[N]) Clamp ¶
func (number *UintBuilder[N]) Clamp(low, high N) *UintBuilder[N]
Clamp limits the value to the range from low to high. It panics with ErrInvalidSchema when low is greater than high. It is a normalizer: it runs before presence, Default and every rule, in the order written.
Example:
schema := validate.Uint(func(number *validate.UintBuilder[uint]) {
number.Clamp(0, 100)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*UintBuilder[N]) Default ¶
func (draft *UintBuilder[N]) Default(value N) *UintBuilder[N]
Default sets the value Parse uses when the prepared input is absent. Registered defaults are checked while a Struct is built; standalone defaults are checked by execution, not metadata export. Input normalizers run before default selection and do not run again on the selected default. Arbitrary default objects retain application ownership. Default cannot be combined with Required.
Example:
type Value struct {
Name string
}
type Form struct {
Value uint
Peer uint
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.UintBuilder[uint]) {
rules.Default(3)
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*UintBuilder[N]) Describe ¶
func (draft *UintBuilder[N]) Describe(text string) *UintBuilder[N]
Describe sets the human-readable description that JSONSchema renders as "description". It does not affect validation. Use it for field and tool descriptions.
Example:
type Value struct {
Name string
}
type Form struct {
Value uint
Peer uint
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.UintBuilder[uint]) {
rules.Describe("A display value")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*UintBuilder[N]) EqField ¶
func (draft *UintBuilder[N]) EqField(field string) *UintBuilder[N]
EqField requires the value to equal the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value uint
Peer uint
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.UintBuilder[uint]) {
rules.EqField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*UintBuilder[N]) ExcludeIf ¶
func (draft *UintBuilder[N]) ExcludeIf(configure ...ConditionBuilderFunc) *UintBuilder[N]
ExcludeIf treats the value as absent, and clears it, when the conditions hold. Later ordinary value constraints skip absence, but later presence constraints still observe it and can report violations. Unconditional preparation may already have run before this rule is evaluated.
Example:
type Value struct {
Name string
}
type Form struct {
Value uint
Peer uint
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.UintBuilder[uint]) {
rules.ExcludeIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*UintBuilder[N]) Gt ¶
func (number *UintBuilder[N]) Gt(limit N) *UintBuilder[N]
Gt requires a value greater than limit.
Example:
schema := validate.Uint(func(number *validate.UintBuilder[uint]) {
number.Gt(1)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*UintBuilder[N]) GtField ¶
func (number *UintBuilder[N]) GtField(field string) *UintBuilder[N]
GtField requires a value greater than the sibling field of the same type.
Example:
type Bounds struct {
Low, High uint
}
schema := validate.Struct(func(object *validate.StructBuilder[Bounds]) {
object.Field("High", func(number *validate.UintBuilder[uint]) {
number.GtField("Low")
})
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*UintBuilder[N]) Gte ¶
func (number *UintBuilder[N]) Gte(limit N) *UintBuilder[N]
Gte requires a value greater than or equal to limit.
Example:
schema := validate.Uint(func(number *validate.UintBuilder[uint]) {
number.Gte(1)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*UintBuilder[N]) GteField ¶
func (number *UintBuilder[N]) GteField(field string) *UintBuilder[N]
GteField requires a value greater than or equal to the sibling field.
Example:
type Bounds struct {
Low, High uint
}
schema := validate.Struct(func(object *validate.StructBuilder[Bounds]) {
object.Field("High", func(number *validate.UintBuilder[uint]) {
number.GteField("Low")
})
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*UintBuilder[N]) Lt ¶
func (number *UintBuilder[N]) Lt(limit N) *UintBuilder[N]
Lt requires a value less than limit.
Example:
schema := validate.Uint(func(number *validate.UintBuilder[uint]) {
number.Lt(100)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*UintBuilder[N]) LtField ¶
func (number *UintBuilder[N]) LtField(field string) *UintBuilder[N]
LtField requires a value less than the sibling field.
Example:
type Bounds struct {
Low, High uint
}
schema := validate.Struct(func(object *validate.StructBuilder[Bounds]) {
object.Field("Low", func(number *validate.UintBuilder[uint]) {
number.LtField("High")
})
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*UintBuilder[N]) Lte ¶
func (number *UintBuilder[N]) Lte(limit N) *UintBuilder[N]
Lte requires a value less than or equal to limit.
Example:
schema := validate.Uint(func(number *validate.UintBuilder[uint]) {
number.Lte(100)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*UintBuilder[N]) LteField ¶
func (number *UintBuilder[N]) LteField(field string) *UintBuilder[N]
LteField requires a value less than or equal to the sibling field.
Example:
type Bounds struct {
Low, High uint
}
schema := validate.Struct(func(object *validate.StructBuilder[Bounds]) {
object.Field("Low", func(number *validate.UintBuilder[uint]) {
number.LteField("High")
})
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*UintBuilder[N]) Max ¶
func (number *UintBuilder[N]) Max(limit N) *UintBuilder[N]
Max allows at most limit.
Example:
schema := validate.Uint(func(number *validate.UintBuilder[uint]) {
number.Max(100)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*UintBuilder[N]) Min ¶
func (number *UintBuilder[N]) Min(limit N) *UintBuilder[N]
Min requires at least limit.
Example:
schema := validate.Uint(func(number *validate.UintBuilder[uint]) {
number.Min(1)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*UintBuilder[N]) MultipleOf ¶
func (number *UintBuilder[N]) MultipleOf(factor N) *UintBuilder[N]
MultipleOf requires a multiple of factor, which must not be zero.
Example:
schema := validate.Uint(func(number *validate.UintBuilder[uint]) {
number.MultipleOf(5)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*UintBuilder[N]) NeField ¶
func (draft *UintBuilder[N]) NeField(field string) *UintBuilder[N]
NeField requires the value to differ from the sibling field of the same type.
Example:
type Value struct {
Name string
}
type Form struct {
Value uint
Peer uint
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.UintBuilder[uint]) {
rules.NeField("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*UintBuilder[N]) NonNegative ¶
func (number *UintBuilder[N]) NonNegative() *UintBuilder[N]
NonNegative is always satisfied by unsigned values and exists for symmetry with the other number schemas.
Example:
schema := validate.Uint(func(number *validate.UintBuilder[uint]) {
number.NonNegative()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*UintBuilder[N]) Normalize ¶
func (draft *UintBuilder[N]) Normalize(fn func(N) N) *UintBuilder[N]
Normalize adds a custom normalizer. It runs before the presence check, Default and every rule, in the order written among the normalizers. It must return the value it is given or a new one, and must not modify its argument. Normalize cannot be used on Map key schemas.
Example:
type Value struct {
Name string
}
type Form struct {
Value uint
Peer uint
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.UintBuilder[uint]) {
rules.Normalize(func(value uint) uint {
return value
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*UintBuilder[N]) NotOneOf ¶
func (number *UintBuilder[N]) NotOneOf(values ...N) *UintBuilder[N]
NotOneOf rejects the listed values.
Example:
schema := validate.Uint(func(number *validate.UintBuilder[uint]) {
number.NotOneOf(13)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*UintBuilder[N]) OneOf ¶
func (number *UintBuilder[N]) OneOf(values ...N) *UintBuilder[N]
OneOf accepts only the listed values.
Example:
schema := validate.Uint(func(number *validate.UintBuilder[uint]) {
number.OneOf(1, 2, 3)
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*UintBuilder[N]) Positive ¶
func (number *UintBuilder[N]) Positive() *UintBuilder[N]
Positive requires a value greater than zero.
Example:
schema := validate.Uint(func(number *validate.UintBuilder[uint]) {
number.Positive()
})
if _, err := schema.JSONSchema(); err != nil {
panic(err)
}
func (*UintBuilder[N]) ProhibitedIf ¶
func (draft *UintBuilder[N]) ProhibitedIf(configure ...ConditionBuilderFunc) *UintBuilder[N]
ProhibitedIf fails when the value is present and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value uint
Peer uint
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.UintBuilder[uint]) {
rules.ProhibitedIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*UintBuilder[N]) ProhibitedUnless ¶
func (draft *UintBuilder[N]) ProhibitedUnless(configure ...ConditionBuilderFunc) *UintBuilder[N]
ProhibitedUnless fails when the value is present and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value uint
Peer uint
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.UintBuilder[uint]) {
rules.ProhibitedUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*UintBuilder[N]) Required ¶
func (draft *UintBuilder[N]) Required() *UintBuilder[N]
Required fails when the value is absent. Absent means zero, or nil for pointers, slices and maps. It cannot be combined with Default.
Example:
type Value struct {
Name string
}
type Form struct {
Value uint
Peer uint
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.UintBuilder[uint]) {
rules.Required()
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*UintBuilder[N]) RequiredIf ¶
func (draft *UintBuilder[N]) RequiredIf(configure ...ConditionBuilderFunc) *UintBuilder[N]
RequiredIf fails when the value is absent and the conditions hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value uint
Peer uint
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.UintBuilder[uint]) {
rules.RequiredIf(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*UintBuilder[N]) RequiredUnless ¶
func (draft *UintBuilder[N]) RequiredUnless(configure ...ConditionBuilderFunc) *UintBuilder[N]
RequiredUnless fails when the value is absent and the conditions do not hold.
Example:
type Value struct {
Name string
}
type Form struct {
Value uint
Peer uint
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.UintBuilder[uint]) {
rules.RequiredUnless(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*UintBuilder[N]) RequiredWith ¶
func (draft *UintBuilder[N]) RequiredWith(fields ...string) *UintBuilder[N]
RequiredWith fails when the value is absent and any of the sibling fields is present.
Example:
type Value struct {
Name string
}
type Form struct {
Value uint
Peer uint
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.UintBuilder[uint]) {
rules.RequiredWith("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*UintBuilder[N]) RequiredWithAll ¶
func (draft *UintBuilder[N]) RequiredWithAll(fields ...string) *UintBuilder[N]
RequiredWithAll fails when the value is absent and all of the sibling fields are present.
Example:
type Value struct {
Name string
}
type Form struct {
Value uint
Peer uint
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.UintBuilder[uint]) {
rules.RequiredWithAll("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*UintBuilder[N]) RequiredWithout ¶
func (draft *UintBuilder[N]) RequiredWithout(fields ...string) *UintBuilder[N]
RequiredWithout fails when the value is absent and any of the sibling fields is absent.
Example:
type Value struct {
Name string
}
type Form struct {
Value uint
Peer uint
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.UintBuilder[uint]) {
rules.RequiredWithout("Peer")
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
func (*UintBuilder[N]) Use ¶
func (draft *UintBuilder[N]) Use(schema Schema[N]) *UintBuilder[N]
Use adds rules from the same published schema role, as a value or nonnil pointer, before subsequent local settings. InferSchema contributes type-only documentation, not validation or missing child definitions. FromJSONSchema provides a separate decoded-JSON API, not a Schema value accepted here. Other schema roles are rejected even when their value type matches, because importing only their base could lose child rules. Schema-level rules accumulate. Overlapping child definitions are construction errors, and later local child callbacks cannot replace an imported child. Ptr permits an unconstrained scalar adapter to yield to a shared pointee. The source remains immutable. Typed nil pointers wrap ErrInvalidSchema.
Example:
var configure validate.UintBuilderFunc[uint] = func(rules *validate.UintBuilder[uint]) {
rules.Use(validate.Uint[uint]())
}
_ = configure
func (*UintBuilder[N]) When ¶
func (draft *UintBuilder[N]) When(condition ConditionBuilderFunc, configure ...func(*UintBuilder[N])) *UintBuilder[N]
When applies additional rules when the condition holds for the enclosing struct. The extra schema runs in place, in the order written, and sees defaults and exclusions like the rest of the chain.
Example:
type Value struct {
Name string
}
type Form struct {
Value uint
Peer uint
Enabled bool
}
schema := validate.Struct(func(object *validate.StructBuilder[Form]) {
object.Field("Value", func(rules *validate.UintBuilder[uint]) {
rules.When(func(predicate *validate.ConditionBuilder) {
predicate.Present("Enabled")
}, func(selected *validate.UintBuilder[uint]) {
selected.Required()
})
})
})
if _, err := schema.JSONSchema(); err != nil { panic(err) }
type UintBuilderFunc ¶
type UintBuilderFunc[N unsigned] = func(*UintBuilder[N])
UintBuilderFunc edits one temporary UintBuilder. Constructors invoke callbacks once, synchronously in order; a nil supplied callback panics.
Example:
var configure validate.UintBuilderFunc[uint] = func(rules *validate.UintBuilder[uint]) {
rules.Required()
}
_ = configure
type UintSchema ¶
type UintSchema[N unsigned] struct {
// contains filtered or unexported fields
}
UintSchema validates unsigned integers, including named types. Construct it with Uint and configure its UintBuilder; the published value is immutable.
WARNING: zero counts as absent and skips every rule except Required, so an optional schema configured with Min(1) accepts 0. Use Required or Ptr when zero is a meaningful value that must be range-checked.
Example:
schema := validate.Uint(func(number *validate.UintBuilder[uint]) {
number.Max(9)
})
if err := schema.Validate(context.Background(), 3); err != nil {
panic(err)
}
func Uint ¶
func Uint[N unsigned](configure ...UintBuilderFunc[N]) UintSchema[N]
Uint publishes a schema for unsigned N, inferred from typed callbacks. Callbacks share one fresh draft and run once in argument order.
Example:
schema := validate.Uint(func(number *validate.UintBuilder[uint64]) {
number.Min(1)
})
if err := schema.Validate(context.Background(), 3); err != nil {
panic(err)
}
func (UintSchema[N]) JSONSchema ¶
func (schema UintSchema[N]) JSONSchema() ([]byte, error)
JSONSchema renders this schema's supported JSON Schema constraints. Runtime-only rules remain enforced by Parse and Validate; invalid schema definitions or values that JSON cannot encode return an error. As with StringSchema.JSONSchema, definition checks never execute validation callbacks; recorded construction errors wrap ErrInvalidSchema.
Example:
schema := validate.Uint[uint]()
document, err := schema.JSONSchema()
if err != nil {
panic(err)
}
_ = document
func (UintSchema[N]) Parse ¶
func (schema UintSchema[N]) Parse(ctx context.Context, v N) (N, error)
Parse checks the input and returns its normalized, defaulted result. It copies storage before applying schema changes and returns the zero value with Errors or a custom Check error when validation fails.
Example:
schema := validate.Uint[uint]()
value, err := schema.Parse(context.Background(), 3)
if err != nil {
panic(err)
}
_ = value
func (UintSchema[N]) Validate ¶
func (schema UintSchema[N]) Validate(ctx context.Context, v N) error
Validate checks the input using the same preparation and rules as Parse, without returning the prepared value. It returns nil, Errors, or a custom Check error; caller-owned input is not modified.
Example:
schema := validate.Uint[uint]()
if err := schema.Validate(context.Background(), 3); err != nil {
panic(err)
}
type Violation ¶
type Violation struct {
// Code identifies the rule, such as "string.min" or "required".
Code string `json:"code"`
// Params holds mutable rule arguments, such as {"min": 3}. Engine-created
// violations from [Fail] or [At] and copies from [Errors.Localize] own their
// parameter containers within the copying limits documented by [Fail].
// [Errors.Add] and [Errors.All] do not copy parameters. Callers must not
// mutate parameters concurrently with readers.
//
// Example:
//
// failures := validate.Errors{"": {{
// Code: "string.min", Params: map[string]any{"min": 3},
// }}}
// localized := failures.Localize(context.Background())
// localized[""][0].Params["min"] = 5
// fmt.Println(failures[""][0].Params["min"]) // 3
Params map[string]any `json:"params,omitzero"`
// Message is the human readable text rendered for the request locale.
Message string `json:"message"`
}
Violation describes one failed rule.
Source Files
¶
- any.go
- assertions.go
- base.go
- boolean.go
- callbacks.go
- catalog.go
- collection.go
- comparison.go
- condition.go
- construction.go
- context.go
- decimal.go
- decoded.go
- doc.go
- duration.go
- embedding.go
- encoded.go
- english.go
- equality.go
- errors.go
- export.go
- file.go
- generate.go
- grammar.go
- infer.go
- map.go
- named.go
- node.go
- number.go
- pointer.go
- predicate.go
- processing.go
- rules.go
- schema.go
- shape.go
- slice.go
- state.go
- string.go
- struct.go
- text.go
- time.go
- wrappers.go
Directories
¶
| Path | Synopsis |
|---|---|
|
internal
|
|
|
encoded
Package encoded implements bounded, exact validation of encoded JSON.
|
Package encoded implements bounded, exact validation of encoded JSON. |
|
faults
Package faults carries error identities shared by the public adapters and private validation engines.
|
Package faults carries error identities shared by the public adapters and private validation engines. |
|
fields
Package fields resolves JSON-v2 field visibility and reflection paths.
|
Package fields resolves JSON-v2 field visibility and reflection paths. |
|
gen
command
Command gen writes wrappers.go: the chain methods that every schema type forwards to the shared base.
|
Command gen writes wrappers.go: the chain methods that every schema type forwards to the shared base. |
|
numbers
Package numbers supplies exact JSON arithmetic shared by validation engines.
|
Package numbers supplies exact JSON arithmetic shared by validation engines. |