Documentation
¶
Overview ¶
Package schematics validates and transforms arbitrary JSON documents against a declarative, data-driven schema.
The model is simple: a document is flattened into dotted keys (for example user.profile.name or tags.0), each schema field targets one or more of those keys (literally, with a * wildcard, or with a full regular expression), and every matched value is run through a chain of validators and operators. Validators report problems as typed ValidationError values; operators transform the value in place.
The package has no third-party dependencies.
Example ¶
Example loads the bundled person schema and prints the validation errors for an invalid document. Errors are reported in schema field order.
package main
import (
"errors"
"fmt"
schematics "github.com/ashbeelghouri/json-schematics-v2"
)
func main() {
s := schematics.New()
if err := s.LoadFile("examples/person.schema.json"); err != nil {
panic(err)
}
data := map[string]any{
"user": map[string]any{
"profile": map[string]any{"name": "a", "age": 200},
"tags": []any{"x", "x"},
},
}
if err := s.Validate(data); err != nil {
var ve *schematics.ValidationErrors
if errors.As(err, &ve) {
for _, msg := range ve.Strings("en", "%target: %message") {
fmt.Println(msg)
}
}
}
}
Output: user.profile.name: name is too short user.profile.age: age must be 0-120 user.tags: items must be unique (duplicate x)
Index ¶
- Constants
- func Deflate(flat map[string]any, separator string) map[string]any
- func Flatten(data map[string]any, separator string) map[string]any
- type API
- type APIEndpoint
- type APIGlobal
- type APISchema
- type Args
- func (a Args) Bool(key string) (bool, error)
- func (a Args) Float(key string) (float64, error)
- func (a Args) FloatOr(key string, def float64) float64
- func (a Args) Get(key string) (any, bool)
- func (a Args) Has(key string) bool
- func (a Args) Int(key string) (int, error)
- func (a Args) String(key string) (string, error)
- func (a Args) StringOr(key, def string) string
- func (a Args) Strings(key string) ([]string, error)
- type Condition
- type ConditionRef
- type Context
- type Field
- type FieldBuilder
- func (fb *FieldBuilder) AddToDB() *FieldBuilder
- func (fb *FieldBuilder) After(date string) *FieldBuilder
- func (fb *FieldBuilder) AfterNow() *FieldBuilder
- func (fb *FieldBuilder) Alpha() *FieldBuilder
- func (fb *FieldBuilder) Alphanumeric() *FieldBuilder
- func (fb *FieldBuilder) Before(date string) *FieldBuilder
- func (fb *FieldBuilder) BeforeNow() *FieldBuilder
- func (fb *FieldBuilder) Between(min, max float64) *FieldBuilder
- func (fb *FieldBuilder) Capitalize() *FieldBuilder
- func (fb *FieldBuilder) Contains(sub string) *FieldBuilder
- func (fb *FieldBuilder) Default(v any) *FieldBuilder
- func (fb *FieldBuilder) DependsOn(targets ...string) *FieldBuilder
- func (fb *FieldBuilder) Description(d string) *FieldBuilder
- func (fb *FieldBuilder) DisplayName(n string) *FieldBuilder
- func (fb *FieldBuilder) Done() *SchemaBuilder
- func (fb *FieldBuilder) Email() *FieldBuilder
- func (fb *FieldBuilder) EndsWith(suffix string) *FieldBuilder
- func (fb *FieldBuilder) Equals(v string) *FieldBuilder
- func (fb *FieldBuilder) ExactLength(n int) *FieldBuilder
- func (fb *FieldBuilder) Field(target string) *FieldBuilder
- func (fb *FieldBuilder) HasDigit() *FieldBuilder
- func (fb *FieldBuilder) HasLower() *FieldBuilder
- func (fb *FieldBuilder) HasUpper() *FieldBuilder
- func (fb *FieldBuilder) InOptions(opts ...string) *FieldBuilder
- func (fb *FieldBuilder) IsArray() *FieldBuilder
- func (fb *FieldBuilder) IsBase64() *FieldBuilder
- func (fb *FieldBuilder) IsBoolean() *FieldBuilder
- func (fb *FieldBuilder) IsCIDR() *FieldBuilder
- func (fb *FieldBuilder) IsDate() *FieldBuilder
- func (fb *FieldBuilder) IsFloat() *FieldBuilder
- func (fb *FieldBuilder) IsHTTPS() *FieldBuilder
- func (fb *FieldBuilder) IsHex() *FieldBuilder
- func (fb *FieldBuilder) IsIP() *FieldBuilder
- func (fb *FieldBuilder) IsInteger() *FieldBuilder
- func (fb *FieldBuilder) IsJSON() *FieldBuilder
- func (fb *FieldBuilder) IsNumber() *FieldBuilder
- func (fb *FieldBuilder) IsObject() *FieldBuilder
- func (fb *FieldBuilder) IsString() *FieldBuilder
- func (fb *FieldBuilder) IsURL() *FieldBuilder
- func (fb *FieldBuilder) IsUUID() *FieldBuilder
- func (fb *FieldBuilder) ItemsInOptions(opts ...string) *FieldBuilder
- func (fb *FieldBuilder) LengthBetween(min, max int) *FieldBuilder
- func (fb *FieldBuilder) Like(p string) *FieldBuilder
- func (fb *FieldBuilder) Lower() *FieldBuilder
- func (fb *FieldBuilder) Max(v float64) *FieldBuilder
- func (fb *FieldBuilder) MaxItems(n int) *FieldBuilder
- func (fb *FieldBuilder) MaxLength(n int) *FieldBuilder
- func (fb *FieldBuilder) Message(msg string) *FieldBuilder
- func (fb *FieldBuilder) Meta(m map[string]any) *FieldBuilder
- func (fb *FieldBuilder) Min(v float64) *FieldBuilder
- func (fb *FieldBuilder) MinItems(n int) *FieldBuilder
- func (fb *FieldBuilder) MinLength(n int) *FieldBuilder
- func (fb *FieldBuilder) MultipleOf(of float64) *FieldBuilder
- func (fb *FieldBuilder) Name(n string) *FieldBuilder
- func (fb *FieldBuilder) Negative() *FieldBuilder
- func (fb *FieldBuilder) New(opts ...Option) (*Schematics, error)
- func (fb *FieldBuilder) NonNegative() *FieldBuilder
- func (fb *FieldBuilder) NotEmpty() *FieldBuilder
- func (fb *FieldBuilder) NotInOptions(opts ...string) *FieldBuilder
- func (fb *FieldBuilder) Op(name string, args Args) *FieldBuilder
- func (fb *FieldBuilder) Pattern(p string) *FieldBuilder
- func (fb *FieldBuilder) Positive() *FieldBuilder
- func (fb *FieldBuilder) Regex() *FieldBuilder
- func (fb *FieldBuilder) Replace(old, new string) *FieldBuilder
- func (fb *FieldBuilder) Required() *FieldBuilder
- func (fb *FieldBuilder) Rule(name string, args Args) *FieldBuilder
- func (fb *FieldBuilder) Schema() Schema
- func (fb *FieldBuilder) Slugify() *FieldBuilder
- func (fb *FieldBuilder) StartsWith(prefix string) *FieldBuilder
- func (fb *FieldBuilder) Tags(tags ...string) *FieldBuilder
- func (fb *FieldBuilder) ToString() *FieldBuilder
- func (fb *FieldBuilder) Trim() *FieldBuilder
- func (fb *FieldBuilder) Truncate(length int, suffix string) *FieldBuilder
- func (fb *FieldBuilder) Type(t string) *FieldBuilder
- func (fb *FieldBuilder) Unique() *FieldBuilder
- func (fb *FieldBuilder) Upper() *FieldBuilder
- func (fb *FieldBuilder) When(condition string, args Args) *FieldBuilder
- func (fb *FieldBuilder) WhenAbsent(field string) *FieldBuilder
- func (fb *FieldBuilder) WhenEquals(field string, value any) *FieldBuilder
- func (fb *FieldBuilder) WhenNot(condition string, args Args) *FieldBuilder
- func (fb *FieldBuilder) WhenPresent(field string) *FieldBuilder
- type FieldView
- type Operator
- type OperatorRef
- type Option
- type Rule
- type RuleRef
- type Schema
- type SchemaBuilder
- func (b *SchemaBuilder) ArrayIDKey(k string) *SchemaBuilder
- func (b *SchemaBuilder) DB(m map[string]any) *SchemaBuilder
- func (b *SchemaBuilder) Field(target string) *FieldBuilder
- func (b *SchemaBuilder) Locale(l string) *SchemaBuilder
- func (b *SchemaBuilder) New(opts ...Option) (*Schematics, error)
- func (b *SchemaBuilder) Schema() Schema
- func (b *SchemaBuilder) Separator(sep string) *SchemaBuilder
- type SchemaError
- type Schematics
- func (s *Schematics) Check() error
- func (s *Schematics) ConditionNames() []string
- func (s *Schematics) LoadBytes(b []byte) error
- func (s *Schematics) LoadFile(path string) error
- func (s *Schematics) LoadMap(m any) error
- func (s *Schematics) Operate(data any) (any, error)
- func (s *Schematics) OperateCtx(ctx context.Context, data any) (any, error)
- func (s *Schematics) OperatorNames() []string
- func (s *Schematics) RegisterCondition(name string, fn Condition) *Schematics
- func (s *Schematics) RegisterOperator(name string, fn Operator) *Schematics
- func (s *Schematics) RegisterRule(name string, fn Rule) *Schematics
- func (s *Schematics) RuleNames() []string
- func (s *Schematics) Schema() Schema
- func (s *Schematics) SetSchema(schema Schema) *Schematics
- func (s *Schematics) Validate(data any) error
- func (s *Schematics) ValidateBytes(b []byte, isArray bool) error
- func (s *Schematics) ValidateBytesCtx(ctx context.Context, b []byte, isArray bool) error
- func (s *Schematics) ValidateCtx(ctx context.Context, data any) error
- func (s *Schematics) ValidateSchema(sample any, ignoreTargets ...string) error
- type ValidationError
- type ValidationErrors
- func (es *ValidationErrors) Add(e *ValidationError)
- func (es *ValidationErrors) Error() string
- func (es *ValidationErrors) ForTarget(target string) []*ValidationError
- func (es *ValidationErrors) HasErrors() bool
- func (es *ValidationErrors) Len() int
- func (es *ValidationErrors) Messages(locale string) []string
- func (es *ValidationErrors) Strings(locale, format string) []string
Examples ¶
Constants ¶
const Version = "2.0"
Version is the schema/library generation this package implements.
Variables ¶
This section is empty.
Functions ¶
func Deflate ¶
Deflate reconstructs a nested structure from a flattened map. Segments that are consecutive integers starting at zero are rebuilt as slices.
func Flatten ¶
Flatten converts a nested map into a single-level map whose keys are the paths to each leaf value, joined by separator. Arrays become indexed keys, so {"tags":["a","b"]} becomes {"tags.0":"a","tags.1":"b"}. Empty maps and slices are preserved as leaf values so length-style validators can still see them.
Flatten/Deflate round-trip losslessly only when object keys do not contain the separator and are non-empty. A literal key like "a.b" is indistinguishable from nested {"a":{"b":...}} once flattened, so if your documents can carry keys containing "." (the default separator), choose a separator that cannot occur in your keys via WithSeparator.
Types ¶
type API ¶
type API struct {
// contains filtered or unexported fields
}
API validates *http.Request values against an APISchema. It reuses a base Schematics for its registries and options, so custom rules registered there are available to request validation too.
func NewAPI ¶
NewAPI creates an API validator with the given options (shared with the underlying engine).
func (*API) Base ¶
func (a *API) Base() *Schematics
Base exposes the underlying Schematics so callers can register custom rules, operators, and conditions used by the request schema.
type APIEndpoint ¶
type APIEndpoint struct {
Path string `json:"path"`
Method string `json:"method"`
Headers []Field `json:"headers,omitempty"`
Query []Field `json:"query,omitempty"`
Body []Field `json:"body,omitempty"`
}
APIEndpoint validates one method+path combination.
type APIGlobal ¶
type APIGlobal struct {
Headers []Field `json:"headers,omitempty"`
}
APIGlobal holds fields applied to every endpoint (currently headers).
type APISchema ¶
type APISchema struct {
Version string `json:"version,omitempty"`
Separator string `json:"separator,omitempty"`
Global APIGlobal `json:"global,omitempty"`
Endpoints []APIEndpoint `json:"endpoints"`
}
APISchema describes request validation for a set of HTTP endpoints. Each endpoint validates its headers, query parameters, and JSON body using the same Field model as the core schema.
Example (JSON):
{
"version": "2.0",
"global": { "headers": [ { "target": "authorization", "required": true } ] },
"endpoints": [
{
"path": "/users/:id",
"method": "POST",
"query": [ { "target": "verbose", "validate": [ { "rule": "inOptions", "args": { "options": ["true","false"] } } ] } ],
"body": [ { "target": "email", "required": true, "validate": [ { "rule": "email" } ] } ]
}
]
}
type Args ¶
Args holds the arguments a schema passes to a validator, operator, or condition. The typed accessors never panic: a missing key or a wrong type is reported as an error instead, which is what makes built-in and custom rules safe to run against arbitrary data.
type ConditionRef ¶
type ConditionRef struct {
Condition string `json:"condition"`
Args Args `json:"args,omitempty"`
Negate bool `json:"negate,omitempty"`
}
ConditionRef references a registered condition. Negate inverts its result.
type Context ¶
type Context struct {
Ctx context.Context
DB map[string]any
Locale string
Separator string
Flat map[string]any
RowID string
Field *FieldView
// contains filtered or unexported fields
}
Context is handed to every validator, operator, and condition. It carries the shared DB, the active locale and separator, the full flattened document, and metadata about the field currently being processed. Ctx is a standard context.Context so long-running custom rules can honor cancellation.
func (*Context) FieldPresent ¶
FieldPresent reports whether target selects at least one value in the document under validation. It honors the active separator and wildcard rules.
type Field ¶
type Field struct {
// Target selects flattened keys: a literal path, a path with a "*"
// wildcard, or (when TargetRegex is true) a regular expression.
Target string `json:"target"`
TargetRegex bool `json:"targetRegex,omitempty"`
Name string `json:"name,omitempty"`
DisplayName string `json:"displayName,omitempty"`
Type string `json:"type,omitempty"`
Description string `json:"description,omitempty"`
// Required fails when the target selects no value.
Required bool `json:"required,omitempty"`
// DependsOn lists other targets that must be present for this field to be
// validated.
DependsOn []string `json:"dependsOn,omitempty"`
// AddToDB copies the matched value into the shared DB before validation, so
// other rules can reference it.
AddToDB bool `json:"addToDB,omitempty"`
Tags []string `json:"tags,omitempty"`
// When lists conditions that must all hold for the field to be processed.
When []ConditionRef `json:"when,omitempty"`
// Validate is the ordered chain of validators. The first failing rule stops
// evaluation of this field and produces one error.
Validate []RuleRef `json:"validate,omitempty"`
// Operate is the ordered chain of operators applied by Operate.
Operate []OperatorRef `json:"operate,omitempty"`
Meta map[string]any `json:"meta,omitempty"`
}
Field targets one or more flattened keys and describes how to validate and transform the matched values.
type FieldBuilder ¶ added in v1.0.2
type FieldBuilder struct {
// contains filtered or unexported fields
}
FieldBuilder accumulates one field's settings, validators, operators, and conditions. Any terminator method (Field, Done, Schema, New) commits it.
func (*FieldBuilder) AddToDB ¶ added in v1.0.2
func (fb *FieldBuilder) AddToDB() *FieldBuilder
AddToDB copies the matched value into the shared DB before validation.
func (*FieldBuilder) After ¶ added in v1.0.2
func (fb *FieldBuilder) After(date string) *FieldBuilder
func (*FieldBuilder) AfterNow ¶ added in v1.0.2
func (fb *FieldBuilder) AfterNow() *FieldBuilder
func (*FieldBuilder) Alpha ¶ added in v1.0.2
func (fb *FieldBuilder) Alpha() *FieldBuilder
func (*FieldBuilder) Alphanumeric ¶ added in v1.0.2
func (fb *FieldBuilder) Alphanumeric() *FieldBuilder
func (*FieldBuilder) Before ¶ added in v1.0.2
func (fb *FieldBuilder) Before(date string) *FieldBuilder
func (*FieldBuilder) BeforeNow ¶ added in v1.0.2
func (fb *FieldBuilder) BeforeNow() *FieldBuilder
func (*FieldBuilder) Between ¶ added in v1.0.2
func (fb *FieldBuilder) Between(min, max float64) *FieldBuilder
func (*FieldBuilder) Capitalize ¶ added in v1.0.2
func (fb *FieldBuilder) Capitalize() *FieldBuilder
func (*FieldBuilder) Contains ¶ added in v1.0.2
func (fb *FieldBuilder) Contains(sub string) *FieldBuilder
func (*FieldBuilder) Default ¶ added in v1.0.2
func (fb *FieldBuilder) Default(v any) *FieldBuilder
func (*FieldBuilder) DependsOn ¶ added in v1.0.2
func (fb *FieldBuilder) DependsOn(targets ...string) *FieldBuilder
DependsOn adds required-present dependency targets.
func (*FieldBuilder) Description ¶ added in v1.0.2
func (fb *FieldBuilder) Description(d string) *FieldBuilder
Description sets the field description.
func (*FieldBuilder) DisplayName ¶ added in v1.0.2
func (fb *FieldBuilder) DisplayName(n string) *FieldBuilder
DisplayName sets the human-facing name.
func (*FieldBuilder) Done ¶ added in v1.0.2
func (fb *FieldBuilder) Done() *SchemaBuilder
Done commits this field and returns the schema builder.
func (*FieldBuilder) Email ¶ added in v1.0.2
func (fb *FieldBuilder) Email() *FieldBuilder
func (*FieldBuilder) EndsWith ¶ added in v1.0.2
func (fb *FieldBuilder) EndsWith(suffix string) *FieldBuilder
func (*FieldBuilder) Equals ¶ added in v1.0.2
func (fb *FieldBuilder) Equals(v string) *FieldBuilder
func (*FieldBuilder) ExactLength ¶ added in v1.0.2
func (fb *FieldBuilder) ExactLength(n int) *FieldBuilder
func (*FieldBuilder) Field ¶ added in v1.0.2
func (fb *FieldBuilder) Field(target string) *FieldBuilder
Field commits this field and starts another.
func (*FieldBuilder) HasDigit ¶ added in v1.0.2
func (fb *FieldBuilder) HasDigit() *FieldBuilder
func (*FieldBuilder) HasLower ¶ added in v1.0.2
func (fb *FieldBuilder) HasLower() *FieldBuilder
func (*FieldBuilder) HasUpper ¶ added in v1.0.2
func (fb *FieldBuilder) HasUpper() *FieldBuilder
func (*FieldBuilder) InOptions ¶ added in v1.0.2
func (fb *FieldBuilder) InOptions(opts ...string) *FieldBuilder
func (*FieldBuilder) IsArray ¶ added in v1.0.2
func (fb *FieldBuilder) IsArray() *FieldBuilder
func (*FieldBuilder) IsBase64 ¶ added in v1.0.2
func (fb *FieldBuilder) IsBase64() *FieldBuilder
func (*FieldBuilder) IsBoolean ¶ added in v1.0.2
func (fb *FieldBuilder) IsBoolean() *FieldBuilder
func (*FieldBuilder) IsCIDR ¶ added in v1.0.2
func (fb *FieldBuilder) IsCIDR() *FieldBuilder
func (*FieldBuilder) IsDate ¶ added in v1.0.2
func (fb *FieldBuilder) IsDate() *FieldBuilder
func (*FieldBuilder) IsFloat ¶ added in v1.0.2
func (fb *FieldBuilder) IsFloat() *FieldBuilder
func (*FieldBuilder) IsHTTPS ¶ added in v1.0.2
func (fb *FieldBuilder) IsHTTPS() *FieldBuilder
func (*FieldBuilder) IsHex ¶ added in v1.0.2
func (fb *FieldBuilder) IsHex() *FieldBuilder
func (*FieldBuilder) IsIP ¶ added in v1.0.2
func (fb *FieldBuilder) IsIP() *FieldBuilder
func (*FieldBuilder) IsInteger ¶ added in v1.0.2
func (fb *FieldBuilder) IsInteger() *FieldBuilder
func (*FieldBuilder) IsJSON ¶ added in v1.0.2
func (fb *FieldBuilder) IsJSON() *FieldBuilder
func (*FieldBuilder) IsNumber ¶ added in v1.0.2
func (fb *FieldBuilder) IsNumber() *FieldBuilder
func (*FieldBuilder) IsObject ¶ added in v1.0.2
func (fb *FieldBuilder) IsObject() *FieldBuilder
func (*FieldBuilder) IsString ¶ added in v1.0.2
func (fb *FieldBuilder) IsString() *FieldBuilder
func (*FieldBuilder) IsURL ¶ added in v1.0.2
func (fb *FieldBuilder) IsURL() *FieldBuilder
func (*FieldBuilder) IsUUID ¶ added in v1.0.2
func (fb *FieldBuilder) IsUUID() *FieldBuilder
func (*FieldBuilder) ItemsInOptions ¶ added in v1.0.2
func (fb *FieldBuilder) ItemsInOptions(opts ...string) *FieldBuilder
func (*FieldBuilder) LengthBetween ¶ added in v1.0.2
func (fb *FieldBuilder) LengthBetween(min, max int) *FieldBuilder
func (*FieldBuilder) Like ¶ added in v1.0.2
func (fb *FieldBuilder) Like(p string) *FieldBuilder
func (*FieldBuilder) Lower ¶ added in v1.0.2
func (fb *FieldBuilder) Lower() *FieldBuilder
func (*FieldBuilder) Max ¶ added in v1.0.2
func (fb *FieldBuilder) Max(v float64) *FieldBuilder
func (*FieldBuilder) MaxItems ¶ added in v1.0.2
func (fb *FieldBuilder) MaxItems(n int) *FieldBuilder
func (*FieldBuilder) MaxLength ¶ added in v1.0.2
func (fb *FieldBuilder) MaxLength(n int) *FieldBuilder
func (*FieldBuilder) Message ¶ added in v1.0.2
func (fb *FieldBuilder) Message(msg string) *FieldBuilder
Message sets the custom message on the most recently added validator.
func (*FieldBuilder) Meta ¶ added in v1.0.2
func (fb *FieldBuilder) Meta(m map[string]any) *FieldBuilder
Meta attaches arbitrary metadata.
func (*FieldBuilder) Min ¶ added in v1.0.2
func (fb *FieldBuilder) Min(v float64) *FieldBuilder
func (*FieldBuilder) MinItems ¶ added in v1.0.2
func (fb *FieldBuilder) MinItems(n int) *FieldBuilder
func (*FieldBuilder) MinLength ¶ added in v1.0.2
func (fb *FieldBuilder) MinLength(n int) *FieldBuilder
func (*FieldBuilder) MultipleOf ¶ added in v1.0.2
func (fb *FieldBuilder) MultipleOf(of float64) *FieldBuilder
func (*FieldBuilder) Name ¶ added in v1.0.2
func (fb *FieldBuilder) Name(n string) *FieldBuilder
Name sets the machine name.
func (*FieldBuilder) Negative ¶ added in v1.0.2
func (fb *FieldBuilder) Negative() *FieldBuilder
func (*FieldBuilder) New ¶ added in v1.0.2
func (fb *FieldBuilder) New(opts ...Option) (*Schematics, error)
New commits this field and builds a checked *Schematics.
func (*FieldBuilder) NonNegative ¶ added in v1.0.2
func (fb *FieldBuilder) NonNegative() *FieldBuilder
func (*FieldBuilder) NotEmpty ¶ added in v1.0.2
func (fb *FieldBuilder) NotEmpty() *FieldBuilder
func (*FieldBuilder) NotInOptions ¶ added in v1.0.2
func (fb *FieldBuilder) NotInOptions(opts ...string) *FieldBuilder
func (*FieldBuilder) Op ¶ added in v1.0.2
func (fb *FieldBuilder) Op(name string, args Args) *FieldBuilder
Op appends an arbitrary operator by name.
func (*FieldBuilder) Pattern ¶ added in v1.0.2
func (fb *FieldBuilder) Pattern(p string) *FieldBuilder
func (*FieldBuilder) Positive ¶ added in v1.0.2
func (fb *FieldBuilder) Positive() *FieldBuilder
func (*FieldBuilder) Regex ¶ added in v1.0.2
func (fb *FieldBuilder) Regex() *FieldBuilder
Regex marks the target as a regular expression.
func (*FieldBuilder) Replace ¶ added in v1.0.2
func (fb *FieldBuilder) Replace(old, new string) *FieldBuilder
func (*FieldBuilder) Required ¶ added in v1.0.2
func (fb *FieldBuilder) Required() *FieldBuilder
Required marks the field required.
func (*FieldBuilder) Rule ¶ added in v1.0.2
func (fb *FieldBuilder) Rule(name string, args Args) *FieldBuilder
Rule appends an arbitrary validator by name.
func (*FieldBuilder) Schema ¶ added in v1.0.2
func (fb *FieldBuilder) Schema() Schema
Schema commits this field and returns the assembled Schema.
func (*FieldBuilder) Slugify ¶ added in v1.0.2
func (fb *FieldBuilder) Slugify() *FieldBuilder
func (*FieldBuilder) StartsWith ¶ added in v1.0.2
func (fb *FieldBuilder) StartsWith(prefix string) *FieldBuilder
func (*FieldBuilder) Tags ¶ added in v1.0.2
func (fb *FieldBuilder) Tags(tags ...string) *FieldBuilder
Tags sets the field tags.
func (*FieldBuilder) ToString ¶ added in v1.0.2
func (fb *FieldBuilder) ToString() *FieldBuilder
func (*FieldBuilder) Trim ¶ added in v1.0.2
func (fb *FieldBuilder) Trim() *FieldBuilder
func (*FieldBuilder) Truncate ¶ added in v1.0.2
func (fb *FieldBuilder) Truncate(length int, suffix string) *FieldBuilder
func (*FieldBuilder) Type ¶ added in v1.0.2
func (fb *FieldBuilder) Type(t string) *FieldBuilder
Type sets the declared type (enforced when the engine has WithTypeChecks).
func (*FieldBuilder) Unique ¶ added in v1.0.2
func (fb *FieldBuilder) Unique() *FieldBuilder
func (*FieldBuilder) Upper ¶ added in v1.0.2
func (fb *FieldBuilder) Upper() *FieldBuilder
func (*FieldBuilder) When ¶ added in v1.0.2
func (fb *FieldBuilder) When(condition string, args Args) *FieldBuilder
When appends a condition that must hold for the field to run.
func (*FieldBuilder) WhenAbsent ¶ added in v1.0.2
func (fb *FieldBuilder) WhenAbsent(field string) *FieldBuilder
func (*FieldBuilder) WhenEquals ¶ added in v1.0.2
func (fb *FieldBuilder) WhenEquals(field string, value any) *FieldBuilder
func (*FieldBuilder) WhenNot ¶ added in v1.0.2
func (fb *FieldBuilder) WhenNot(condition string, args Args) *FieldBuilder
WhenNot appends a negated condition.
func (*FieldBuilder) WhenPresent ¶ added in v1.0.2
func (fb *FieldBuilder) WhenPresent(field string) *FieldBuilder
type FieldView ¶
type FieldView struct {
Target string
Name string
Type string
Required bool
Provided bool
Tags []string
}
FieldView is a read-only snapshot of the field a rule is running against.
type Operator ¶
Operator transforms a value and returns the replacement. Returning an error aborts the whole Operate call.
type OperatorRef ¶
OperatorRef references a registered operator and its arguments.
type Option ¶
type Option func(*Schematics)
Option configures a Schematics at construction time.
func WithArrayIDKey ¶
WithArrayIDKey sets the flattened key whose value identifies each row when validating an array of objects.
func WithCollectAll ¶ added in v1.0.2
func WithCollectAll() Option
WithCollectAll makes Validate report every failing rule on each field rather than stopping at the first failure. Useful for form validation where the caller wants to show all problems at once.
func WithLocale ¶
WithLocale sets the default locale for error messages.
func WithLogger ¶
WithLogger attaches a slog.Logger. By default logs are discarded.
func WithMaxBodyBytes ¶ added in v1.0.2
WithMaxBodyBytes caps how many bytes the API layer reads from a request body, guarding against unbounded-read denial of service. A value <= 0 means unlimited. It has no effect on the plain Validate path.
func WithSeparator ¶
WithSeparator sets the key separator used when flattening documents.
func WithTypeChecks ¶ added in v1.0.2
func WithTypeChecks() Option
WithTypeChecks makes a field's "type" enforce a matching built-in check (string, number, integer, boolean, array, date, object) before its own validators run. Without this option, "type" is treated as documentation only, preserving the default behavior.
type Rule ¶
Rule validates a value. It returns nil when the value is acceptable, or an error describing why it is not. Rules must never panic: use the typed Args accessors and the value-inspection helpers, both of which report bad input as errors.
type RuleRef ¶
type RuleRef struct {
Rule string `json:"rule"`
Args Args `json:"args,omitempty"`
Message string `json:"message,omitempty"`
Messages map[string]string `json:"messages,omitempty"`
}
RuleRef references a registered validator and its per-use configuration.
type Schema ¶
type Schema struct {
Version string `json:"version,omitempty"`
Separator string `json:"separator,omitempty"`
ArrayIDKey string `json:"arrayIdKey,omitempty"`
Locale string `json:"locale,omitempty"`
DB map[string]any `json:"db,omitempty"`
Fields []Field `json:"fields"`
}
Schema is the declarative document that drives validation and operation.
Example (JSON):
{
"version": "2.0",
"separator": ".",
"arrayIdKey": "id",
"locale": "en",
"db": { "minAge": 18 },
"fields": [
{
"target": "user.profile.name",
"type": "string",
"required": true,
"validate": [ { "rule": "minLength", "args": { "min": 2 } } ],
"operate": [ { "op": "trim" }, { "op": "capitalize" } ]
}
]
}
type SchemaBuilder ¶ added in v1.0.2
type SchemaBuilder struct {
// contains filtered or unexported fields
}
SchemaBuilder accumulates schema-level settings and fields.
func NewSchema ¶ added in v1.0.2
func NewSchema() *SchemaBuilder
NewSchema starts a fluent schema definition.
func (*SchemaBuilder) ArrayIDKey ¶ added in v1.0.2
func (b *SchemaBuilder) ArrayIDKey(k string) *SchemaBuilder
ArrayIDKey sets the per-row identifier key for array validation.
func (*SchemaBuilder) DB ¶ added in v1.0.2
func (b *SchemaBuilder) DB(m map[string]any) *SchemaBuilder
DB seeds the shared DB baked into the schema.
func (*SchemaBuilder) Field ¶ added in v1.0.2
func (b *SchemaBuilder) Field(target string) *FieldBuilder
Field begins a new field targeting target.
func (*SchemaBuilder) Locale ¶ added in v1.0.2
func (b *SchemaBuilder) Locale(l string) *SchemaBuilder
Locale sets the default error locale.
func (*SchemaBuilder) New ¶ added in v1.0.2
func (b *SchemaBuilder) New(opts ...Option) (*Schematics, error)
New builds a *Schematics from the schema, applies opts, and runs Check so a malformed schema fails fast.
func (*SchemaBuilder) Schema ¶ added in v1.0.2
func (b *SchemaBuilder) Schema() Schema
Schema returns the assembled Schema value.
func (*SchemaBuilder) Separator ¶ added in v1.0.2
func (b *SchemaBuilder) Separator(sep string) *SchemaBuilder
Separator sets the flattening separator.
type SchemaError ¶
type SchemaError struct {
Problems []string
}
SchemaError is returned when a schema references a rule, operator, or condition that is not registered, or is otherwise malformed. It is distinct from ValidationErrors, which reports problems with the data.
func (*SchemaError) Error ¶
func (e *SchemaError) Error() string
type Schematics ¶
type Schematics struct {
// contains filtered or unexported fields
}
Schematics is the entry point: it holds a schema, the registries of validators/operators/conditions (pre-loaded with the built-ins), and configuration. Create one with New, load a schema, then call Validate or Operate.
A Schematics is safe for concurrent use by multiple goroutines once its schema is loaded and any custom rules are registered: Validate, ValidateCtx, Operate, ValidateBytes and the API layer may all be called in parallel on a shared instance. Registering rules or loading a new schema is not safe to do concurrently with validation — do that during setup, before sharing.
func ImportSchema ¶ added in v1.0.2
func ImportSchema(b []byte, opts ...Option) (*Schematics, error)
ImportSchema is a convenience constructor for callers who start from raw schema bytes (a config file already read into memory, a network response, an embedded fixture): it combines New and LoadBytes into one call.
s, err := schematics.ImportSchema(schemaBytes)
if err != nil {
log.Fatal(err)
}
Any options are applied the same way they are for New, before the schema is loaded.
func New ¶
func New(opts ...Option) *Schematics
New creates a Schematics with every built-in validator, operator, and condition registered, then applies the given options.
func (*Schematics) Check ¶
func (s *Schematics) Check() error
Check verifies that every rule, operator, and condition referenced by the schema is registered and that fields are well formed. It returns a *SchemaError describing all problems, or nil.
func (*Schematics) ConditionNames ¶
func (s *Schematics) ConditionNames() []string
ConditionNames returns the names of every registered condition.
func (*Schematics) LoadBytes ¶
func (s *Schematics) LoadBytes(b []byte) error
LoadBytes parses a JSON schema from b.
func (*Schematics) LoadFile ¶
func (s *Schematics) LoadFile(path string) error
LoadFile reads and parses a JSON schema file.
func (*Schematics) LoadMap ¶
func (s *Schematics) LoadMap(m any) error
LoadMap parses a schema from an in-memory value (a map or struct) by round-tripping it through JSON.
func (*Schematics) Operate ¶
func (s *Schematics) Operate(data any) (any, error)
Operate applies each field's operator chain to the matching values in data and returns the transformed document. data may be a single object or an array of objects. Validators are not run.
func (*Schematics) OperateCtx ¶
OperateCtx is Operate with a caller-supplied context.Context.
func (*Schematics) OperatorNames ¶
func (s *Schematics) OperatorNames() []string
OperatorNames returns the names of every registered operator.
func (*Schematics) RegisterCondition ¶
func (s *Schematics) RegisterCondition(name string, fn Condition) *Schematics
RegisterCondition adds or replaces a named condition.
func (*Schematics) RegisterOperator ¶
func (s *Schematics) RegisterOperator(name string, fn Operator) *Schematics
RegisterOperator adds or replaces a named operator.
func (*Schematics) RegisterRule ¶
func (s *Schematics) RegisterRule(name string, fn Rule) *Schematics
RegisterRule adds or replaces a named validator. It is safe to call after loading a schema and before Validate.
func (*Schematics) RuleNames ¶
func (s *Schematics) RuleNames() []string
RuleNames returns the names of every registered validator.
func (*Schematics) Schema ¶
func (s *Schematics) Schema() Schema
Schema returns the currently loaded schema.
func (*Schematics) SetSchema ¶
func (s *Schematics) SetSchema(schema Schema) *Schematics
SetSchema installs a schema value directly.
func (*Schematics) Validate ¶
func (s *Schematics) Validate(data any) error
Validate checks data against the loaded schema. data may be a single object (map or struct) or an array of objects. It returns nil when the data is valid, a *ValidationErrors when it is not, or a *SchemaError when the schema itself references something unregistered.
func (*Schematics) ValidateBytes ¶ added in v1.0.2
func (s *Schematics) ValidateBytes(b []byte, isArray bool) error
ValidateBytes parses raw JSON data bytes and validates them against the loaded schema, saving the caller a manual json.Unmarshal before calling Validate. isArray tells it whether to parse b as a single JSON object (false) or as an array of objects (true) — pass it explicitly rather than relying on shape-sniffing, so a payload that doesn't match the expected shape fails with a clear parse error instead of silently going through Validate's try-object-then-array fallback.
func (*Schematics) ValidateBytesCtx ¶ added in v1.0.2
ValidateBytesCtx is ValidateBytes with a caller-supplied context.Context, made available to every rule via Context.Ctx.
func (*Schematics) ValidateCtx ¶
func (s *Schematics) ValidateCtx(ctx context.Context, data any) error
ValidateCtx is Validate with a caller-supplied context.Context, made available to every rule via Context.Ctx.
func (*Schematics) ValidateSchema ¶ added in v1.0.1
func (s *Schematics) ValidateSchema(sample any, ignoreTargets ...string) error
ValidateSchema runs every check that Check does — unknown rule/operator/ condition names, empty targets, duplicate targets — and additionally verifies that every field's target actually resolves against sample once flattened. sample should be a representative example of the data you intend to validate: a test fixture, a golden payload, or real (secret- stripped) production data.
Check alone cannot catch a typo inside a target's value. Given `"target": "mane"` instead of `"name"`, "mane" is a perfectly valid string, so Check has nothing to object to — the field just silently never matches anything at runtime. ValidateSchema closes that gap by matching every target against real data and flagging the ones that match nothing.
A typo in the JSON *key* itself — `"tagret"` instead of `"target"` — never needs sample data to catch: encoding/json silently drops an unrecognized key, so Target is left as "" and Check already reports "field #N has an empty target". ValidateSchema surfaces that too, since it runs Check first.
Pass ignoreTargets for fields that are legitimately allowed to be missing from every sample you have — an optional field with no example value in your fixtures, say — so they are not flagged as suspected typos.
Wildcard (target containing "*") and targetRegex fields are matched the same way they are at validation time: if nothing in sample matches the pattern, the field is flagged. If that's simply because your sample doesn't happen to contain that shape, add the target to ignoreTargets rather than treating the result as a bug in the schema.
ValidateSchema does not replace tests. It is meant to run in CI or a unit test alongside a fixture, so drift between your schema and your real data shape fails the build instead of failing silently in production.
type ValidationError ¶
type ValidationError struct {
// Target is the concrete flattened key that failed, e.g. "user.profile.name".
Target string
// Rule is the name of the validator (or "required"/"dependsOn") that failed.
Rule string
// Value is the offending value.
Value any
// RowID identifies the array row for array inputs; empty for plain objects.
RowID string
// contains filtered or unexported fields
}
ValidationError describes a single rule that failed on a single target value.
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string
Error implements the error interface using the default locale.
func (*ValidationError) Format ¶
func (e *ValidationError) Format(locale, format string) string
Format renders the error using a template. Recognized tokens are %message, %target, %rule (alias %validator), %value and %id.
func (*ValidationError) MarshalJSON ¶
func (e *ValidationError) MarshalJSON() ([]byte, error)
MarshalJSON renders the error as a stable JSON object.
func (*ValidationError) Message ¶
func (e *ValidationError) Message(locale string) string
Message returns the message for locale, falling back to the default message and then to a generated description.
type ValidationErrors ¶
type ValidationErrors struct {
Errors []*ValidationError
}
ValidationErrors is the aggregate error returned by Validate. It implements the error interface, so callers can use errors.As to recover it.
func (*ValidationErrors) Add ¶
func (es *ValidationErrors) Add(e *ValidationError)
Add appends a non-nil error.
func (*ValidationErrors) Error ¶
func (es *ValidationErrors) Error() string
Error implements the error interface.
func (*ValidationErrors) ForTarget ¶
func (es *ValidationErrors) ForTarget(target string) []*ValidationError
ForTarget returns the subset of errors whose Target equals target.
func (*ValidationErrors) HasErrors ¶
func (es *ValidationErrors) HasErrors() bool
HasErrors reports whether any errors were collected.
func (*ValidationErrors) Len ¶
func (es *ValidationErrors) Len() int
Len returns the number of collected errors.
func (*ValidationErrors) Messages ¶
func (es *ValidationErrors) Messages(locale string) []string
Messages returns just the localized messages.
func (*ValidationErrors) Strings ¶
func (es *ValidationErrors) Strings(locale, format string) []string
Strings renders every error with the given locale and format template.