From f6b8fe281c2dea4d14d3e457bd0b9bf006d6e02c Mon Sep 17 00:00:00 2001 From: wofiporia <1029687661@qq.com> Date: Tue, 10 Mar 2026 11:12:29 +0800 Subject: [PATCH] docs: add Valuer interface documentation and example Add documentation for the Valuer interface introduced in #1416. - add Valuer interface section and example snippet in doc.go - add a new runnable example at _examples/valuer/ main.go - add Valuer Interface entry in README examples list Refs #1538 --- README.md | 2 +- _examples/valuer/main.go | 57 ++++++++++++++++++++++++++++++++++++++++ doc.go | 34 ++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 _examples/valuer/main.go diff --git a/README.md b/README.md index 1935e436..9b0a995e 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ It has the following **unique** features: - Slice, Array and Map diving, which allows any or all levels of a multidimensional field to be validated. - Ability to dive into both map keys and values for validation - Handles type interface by determining it's underlying type prior to validation. -- Handles custom field types such as sql driver Valuer see [Valuer](https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29) +- Handles custom field types such as sql driver [Valuer](https://golang.org/src/database/sql/driver/types.go?s=1210:1293#L29) and the [Valuer interface](https://github.com/go-playground/validator/blob/master/_examples/valuer/main.go) - Alias validation tags, which allows for mapping of several validations to a single tag for easier defining of validations on structs - Extraction of custom defined Field Name e.g. can specify to extract the JSON name while validating and have it available in the resulting FieldError - Customizable i18n aware error messages. diff --git a/_examples/valuer/main.go b/_examples/valuer/main.go new file mode 100644 index 00000000..8a690258 --- /dev/null +++ b/_examples/valuer/main.go @@ -0,0 +1,57 @@ +package main + +import ( + "errors" + "fmt" + + "github.com/go-playground/validator/v10" +) + +// Nullable wraps a generic value. +type Nullable[T any] struct { + Data T +} + +// ValidatorValue returns the inner value that should be validated. +func (n Nullable[T]) ValidatorValue() any { + return n.Data +} + +type Config struct { + Name string `validate:"required"` +} + +type Record struct { + Config Nullable[Config] `validate:"required"` +} + +// use a single instance of Validate, it caches struct info +var validate *validator.Validate + +func main() { + validate = validator.New() + + // valid case: ValidatorValue unwraps Config and Name passes required. + valid := Record{ + Config: Nullable[Config]{ + Data: Config{Name: "validator"}, + }, + } + err := validate.Struct(valid) + if err != nil { + fmt.Printf("Err(s):\n%+v\n", err) + } + + // invalid case: Name is empty after unwrapping, so required fails on Config.Name. + invalid := Record{ + Config: Nullable[Config]{}, + } + err = validate.Struct(invalid) + if err != nil { + fmt.Printf("Err(s):\n%+v\n", err) + var validationErrs validator.ValidationErrors + if errors.As(err, &validationErrs) && len(validationErrs) > 0 { + fmt.Printf("First error namespace: %s\n", validationErrs[0].Namespace()) + } + } +} diff --git a/doc.go b/doc.go index 9e802898..dab05bee 100644 --- a/doc.go +++ b/doc.go @@ -52,6 +52,40 @@ Custom Validation functions can be added. Example: // NOTES: using the same tag name as an existing function // will overwrite the existing one +# Valuer Interface + +Custom types can implement the Valuer interface to return the value that should +be validated. This is useful when a type wraps another value and you want +validation to run against the unwrapped value. + + type Nullable[T any] struct { + Data T + } + + func (n Nullable[T]) ValidatorValue() any { + return n.Data + } + + type Config struct { + Name string `validate:"required"` + } + + type Record struct { + Config Nullable[Config] `validate:"required"` + } + + r := Record{ + Config: Nullable[Config]{ + Data: Config{Name: "validator"}, + }, + } + + err := validate.Struct(r) + +The library also supports types like sql/driver.Valuer using +RegisterCustomTypeFunc. See _examples/valuer/main.go and +_examples/custom/main.go for both approaches. + # Cross-Field Validation Cross-Field Validation can be done via the following tags: