Examples
Minimal example
package main
import (
"context"
"encoding/json"
"errors"
"fmt"
"time"
"github.com/ygrebnov/model"
modelvalidation "github.com/ygrebnov/model/validation"
)
type Cfg struct {
Name string `default:"svc" validate:"min(3),max(20)"`
Wait time.Duration `default:"500ms"`
}
func main() {
cfg := Cfg{}
m, err := model.New(&cfg,
model.WithDefaults[Cfg](),
model.WithValidation[Cfg](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("OK: %+v\n", cfg)
}
Reusable validation with Binding[T]
Use Binding[T] when many objects share the same schema.
package main
import (
"context"
"fmt"
"github.com/ygrebnov/model"
)
type Payload struct {
ID string `validate:"uuid"`
Email string `validate:"email"`
Retries int `validate:"min(0),max(5)"`
}
func main() {
b, err := model.NewBinding[Payload]()
if err != nil {
panic(err)
}
fmt.Println(b.ValidateWithDefaults(context.Background(), &p) == nil)
}
Output:
true
Custom rule with validation.NewRule
package main
import (
"context"
"errors"
"fmt"
"strconv"
"github.com/ygrebnov/model"
modelvalidation "github.com/ygrebnov/model/validation"
)
type Comment struct {
Text string `validate:"minLen(3)"`
}
func main() {
minLen, _ := modelvalidation.NewRule[string]("minLen", func(s string, params ...string) error {
n, _ := strconv.Atoi(params[0])
if len(s) < n {
return fmt.Errorf("must be at least %d chars", n)
}
return nil
})
c := Comment{Text: "xy"}
m, _ := model.New(&c, model.WithRules[Comment](minLen))
err := m.Validate(context.Background())
var ve *modelvalidation.Error
fmt.Println(errors.As(err, &ve))
fmt.Println(err)
}
Output:
true
- Field "Text": rule "minLen": must be at least 3 chars
Inspect validation failures
model returns a *validation.Error, which groups issues by field and preserves the underlying rule errors.
package main
import (
"context"
"errors"
"fmt"
"github.com/ygrebnov/model"
modelvalidation "github.com/ygrebnov/model/validation"
)
type Account struct {
Email string `validate:"email"`
}
func main() {
a := Account{Email: "bad"}
_, err := model.New(&a, model.WithValidation[Account](context.Background()))
var ve *modelvalidation.Error
if errors.As(err, &ve) {
fmt.Println(ve.Fields())
fmt.Println(len(ve.ForField("Email")))
}
}
Output:
[Email]
1
Structured errors with errorc and keys
Internally, model uses the companion errorc and keys libraries to build low-level structured rule errors.
In application code, that usually means:
- use
errors.As(err, &ve)to access*validation.Error - use
errors.Is(...)against sentinels fromgithub.com/ygrebnov/model/errors - inspect
FieldError.Errif you need lower-level structured metadata
If your application already standardizes structured errors with errorc, model integrates naturally into that style.
Running the examples
The examples live directly in the package as Example* functions and are executed by go test.
# run unit tests and example functions
go test ./...
# run only examples
go test -run Example ./...
Browse examples:
- On pkg.go.dev: https://pkg.go.dev/github.com/ygrebnov/model
- In the repository: search for
Examplefunctions inside*.gofiles.