Skip to main content

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)
}

p := Payload{ID: "123e4567-e89b-12d3-a456-426614174000", Email: "[email protected]", Retries: 1}
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 from github.com/ygrebnov/model/errors
  • inspect FieldError.Err if 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: