Overview
model — defaults & validation for Go structs
model is a small Go library for applying defaults and validation to structs using field tags.
It offers two entry points:
model.New(...)creates aModel[T]bound to a single struct instance.model.NewBinding[T]()creates a reusableBinding[T]that can be applied to many values of the same type.
The library can:
- Set defaults from struct tags like
default:"…"anddefaultElem:"…". - Validate fields using named rules from
validate:"…"andvalidateElem:"…". - Accumulate all issues into a single
*validation.Errorinstead of failing fast. - Recurse through nested structs, pointers, slices/arrays, and map values.
It is designed to be small, explicit, and type-safe. You can register custom rules with validation.NewRule(...), while built-ins such as min, max, email, uuid, nonzero, and oneof(...) are available automatically.
Internally, model uses the companion errorc and keys libraries to attach structured metadata to validation and rule errors.
- Repository: github.com/ygrebnov/model
- API Docs: pkg.go.dev/github.com/ygrebnov/model
Quick start
package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"time"
"github.com/ygrebnov/model"
modelvalidation "github.com/ygrebnov/model/validation"
)
type User struct {
Name string `default:"Anonymous" validate:"min(3),max(50)"`
Age int `default:"18" validate:"min(1),nonzero"`
Timeout time.Duration `default:"1s"`
}
func main() {
u := User{}
m, err := model.New(&u,
model.WithDefaults[User](),
model.WithValidation[User](context.Background()),
)
if err != nil {
var ve *modelvalidation.Error
if errors.As(err, &ve) {
b, _ := json.MarshalIndent(ve, "", " ")
fmt.Println(string(b))
} else {
fmt.Println("error:", err)
}
return
}
_ = m
fmt.Printf("User after defaults: %+v\n", u)
}
Why use it?
- Explicit and predictable: defaults only fill zero values; validation collects all failures.
- Reusable:
Binding[T]lets you build one validation/defaulting engine and apply it to many objects. - Extensible: add custom rules for concrete types or interfaces.
- Structured diagnostics: underlying rule errors carry metadata built with
errorcandkeys.
Common workflows
Single object: Model[T]
Use model.New(...) when you want to bind one struct instance and optionally apply defaults and validation immediately.
Reusable engine: Binding[T]
Use model.NewBinding[T]() when many requests or records share the same struct type.
b, err := model.NewBinding[User]()
if err != nil {
panic(err)
}
u := User{}
if err := b.ValidateWithDefaults(context.Background(), &u); err != nil {
fmt.Println(err)
}
Structured errors and companion projects
Validation failures are returned as *validation.Error, which groups FieldError values by field path. Internally, many of the underlying rule errors use structured metadata built with:
That makes model a good fit when you want both human-readable messages and machine-friendly error metadata.
See Installation and Examples for more.