validation

package module
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 19, 2026 License: MIT Imports: 15 Imported by: 3

README

validation

GoDoc Go Report

Description

This package is a fork of the original https://github.com/go-ozzo/ozzo-validation

validation is a Go package that provides configurable and extensible data validation capabilities. It has the following features:

  • use normal programming constructs rather than error-prone struct tags to specify how data should be validated.
  • can validate data of different types, e.g., structs, strings, byte slices, slices, maps, arrays.
  • can validate custom data types as long as they implement the Validatable interface.
  • can validate data types that implement the sql.Valuer interface (e.g. sql.NullString).
  • customizable and well-formatted validation errors.
  • error code and message translation support.
  • provide a rich set of validation rules right out of box.
  • extremely easy to create and use custom validation rules.

Requirements

Go 1.24 or above.

Getting Started

This package mainly includes a set of validation rules and several validation methods. You use validation rules to describe how a value should be considered valid, and you call validation.Validate(), validation.ValidateStruct(), or validation.Map() to validate the value. Many of the rules are generic, so the value you compare against is type-checked at compile time.

Installation

Run the following command to install the package:

go get github.com/monetr/validation
Validating a Simple Value

For a simple value, such as a string or an integer, you may use validation.Validate() to validate it. For example,

package main

import (
	"fmt"

	"github.com/monetr/validation"
	"github.com/monetr/validation/is"
)

func main() {
	data := "example"
	err := validation.Validate(data,
		validation.Required,       // not empty
		validation.Length(5, 100), // length between 5 and 100
		is.URL,                    // is a valid URL
	)
	fmt.Println(err)
	// Output:
	// must be a valid URL
}

The method validation.Validate() will run through the rules in the order that they are listed. If a rule fails the validation, the method will return the corresponding error and skip the rest of the rules. The method will return nil if the value passes all validation rules.

Validating a Struct

For a struct value, you usually want to check if its fields are valid. For example, in a RESTful application, you may unmarshal the request payload into a struct and then validate the struct fields. If one or multiple fields are invalid, you may want to get an error describing which fields are invalid. You can use validation.ValidateStruct() to achieve this purpose. A single struct can have rules for multiple fields, and a field can be associated with multiple rules. For example,

type Address struct {
	Street string
	City   string
	State  string
	Zip    string
}

func (a Address) Validate() error {
	return validation.ValidateStruct(&a,
		// Street cannot be empty, and the length must between 5 and 50
		validation.Field(&a.Street, validation.Required, validation.Length(5, 50)),
		// City cannot be empty, and the length must between 5 and 50
		validation.Field(&a.City, validation.Required, validation.Length(5, 50)),
		// State cannot be empty, and must be a string consisting of two letters in upper case
		validation.Field(&a.State, validation.Required, validation.Match(regexp.MustCompile("^[A-Z]{2}$"))),
		// State cannot be empty, and must be a string consisting of five digits
		validation.Field(&a.Zip, validation.Required, validation.Match(regexp.MustCompile("^[0-9]{5}$"))),
	)
}

a := Address{
    Street: "123",
    City:   "Unknown",
    State:  "Virginia",
    Zip:    "12345",
}

err := a.Validate()
fmt.Println(err)
// Output:
// Street: the length must be between 5 and 50; State: must be in a valid format.

Note that when calling validation.ValidateStruct to validate a struct, you should pass to the method a pointer to the struct instead of the struct itself. Similarly, when calling validation.Field to specify the rules for a struct field, you should use a pointer to the struct field.

When the struct validation is performed, the fields are validated in the order they are specified in ValidateStruct. And when each field is validated, its rules are also evaluated in the order they are associated with the field. If a rule fails, an error is recorded for that field, and the validation will continue with the next field.

Validating a Map

Sometimes you might need to work with dynamic data stored in maps rather than a typed model. You can use validation.Map() in this situation. A single map can have rules for multiple keys, and a key can be associated with multiple rules. For example,

c := map[string]interface{}{
	"Name":  "Qiang Xue",
	"Email": "q",
	"Address": map[string]interface{}{
		"Street": "123",
		"City":   "Unknown",
		"State":  "Virginia",
		"Zip":    "12345",
	},
}

err := validation.Validate(c,
	validation.Map(
		// Name cannot be empty, and the length must be between 5 and 20.
		validation.Key("Name", validation.Required, validation.Length(5, 20)),
		// Email cannot be empty and should be in a valid email format.
		validation.Key("Email", validation.Required, is.Email),
		// Validate Address using its own validation rules
		validation.Key("Address", validation.Map(
			// Street cannot be empty, and the length must between 5 and 50
			validation.Key("Street", validation.Required, validation.Length(5, 50)),
			// City cannot be empty, and the length must between 5 and 50
			validation.Key("City", validation.Required, validation.Length(5, 50)),
			// State cannot be empty, and must be a string consisting of two letters in upper case
			validation.Key("State", validation.Required, validation.Match(regexp.MustCompile("^[A-Z]{2}$"))),
			// State cannot be empty, and must be a string consisting of five digits
			validation.Key("Zip", validation.Required, validation.Match(regexp.MustCompile("^[0-9]{5}$"))),
		)),
	),
)
fmt.Println(err)
// Output:
// Address: (State: must be in a valid format; Street: the length must be between 5 and 50.); Email: must be a valid email address.

When the map validation is performed, the keys are validated in the order they are specified in Map. And when each key is validated, its rules are also evaluated in the order they are associated with the key. If a rule fails, an error is recorded for that key, and the validation will continue with the next key.

Validating Unions (one-of)

Sometimes a value is valid if it matches one of several shapes — a discriminated union. A login payload, for example, might be {email, password} or {username, password}, but never both. The MatchOneOf family validates a value against a set of alternative schemas: the first schema that fully validates wins, and its index is returned so you can act on the matched shape (parse it, merge it, branch on it). If none match, a OneOfError is returned describing every alternative that was tried.

Maps

A map schema is just a Map(...) rule, and a variant forbids a field simply by not listing itMap already reports unlisted keys as "key not expected" (unless you call AllowExtraKeys), so no special "forbidden" rule is needed.

withEmail := validation.Map(
	validation.Key("email", validation.Required, is.EmailFormat),
	validation.Key("password", validation.Required),
)
withUsername := validation.Map(
	validation.Key("username", validation.Required),
	validation.Key("password", validation.Required),
)

i, err := validation.MatchOneOf(input, withEmail, withUsername)
// i == 0  -> matched withEmail
// i == 1  -> matched withUsername
// i == -1 -> err is a OneOfError describing both attempts

Use MatchOneOfWithContext to thread a context.Context through to the schema rules.

Structs

In a struct every field always exists (as its zero value), so a variant marks the fields it forbids with the Never rule. MatchOneOfStruct takes a pointer to the struct and one []*FieldRules per variant:

emailLogin := []*validation.FieldRules{
	validation.Field(&l.Email, validation.Required, is.EmailFormat),
	validation.Field(&l.Password, validation.Required),
	validation.Field(&l.Username, validation.Never), // forbidden in this variant
}
usernameLogin := []*validation.FieldRules{
	validation.Field(&l.Email, validation.Never),
	validation.Field(&l.Username, validation.Required),
	validation.Field(&l.Password, validation.Required),
}

i, err := validation.MatchOneOfStruct(ctx, &l, emailLogin, usernameLogin)

Never gives pointer fields nil semantics (a present pointer fails even if it points at an empty value) and non-pointer fields zero-value semantics (an empty string or 0 passes).

The OneOf rule and strict matching

When you only need pass/fail and not the winning index, OneOf(schemas ...Rule) is the rule form and composes anywhere a Rule is accepted:

err := validation.Validate(input, validation.OneOf(withEmail, withUsername))

By default the first matching schema wins (anyOf semantics). Call .Strict() to require that exactly one schema match; if more than one does, it fails with ErrAmbiguousMatch — a useful guard against schemas that are not mutually exclusive.

Per-field unions with AllOf

OneOf treats each alternative as a single Rule, which is exactly what you want when each branch is a whole map or struct schema. But sometimes a single field needs to match one set of rules OR a different set — for example a key that must either be null, OR be a present string of a certain length and shape. OneOf alone can't express the multi-rule branch because it only takes one rule per alternative. AllOf(rules ...Rule) bundles several rules into one (the AND counterpart to OneOf's OR) so it can stand in as a branch:

keyPattern := regexp.MustCompile(`^[a-z0-9_]+$`)

err := validation.Validate(key, validation.OneOf(
    validation.Nil, // either the key is absent,
    validation.AllOf( // OR it is present and satisfies all three rules.
        validation.Required,
        validation.Length(10, 64),
        validation.Match(keyPattern),
    ),
))

The single-rule branch (Nil) needs no AllOf — a lone Rule is already a valid alternative. AllOf only earns its keep on branches made of more than one rule. Like Validate, it runs its rules in order and stops at the first failure, so when an AllOf branch fails the OneOfError records the specific sub-rule that did not pass rather than a merged blob. It threads context.Context through to its rules, so a context-aware rule (or a nested OneOf) inside the set still sees it.

Nesting unions

Because OneOf and AllOf are both ordinary Rules, they compose to any depth — a union can be a branch of another union, and a single field inside one variant can carry a union of its own. A realistic case is a discriminated union of object shapes (told apart by a type field) where one of those shapes has a field that is itself a small union:

// A notification destination is one of three shapes, distinguished by "type".
emailDest := validation.Map(
	validation.Key("type", validation.Required, validation.In("email")),
	validation.Key("address", validation.Required, is.EmailFormat),
)
webhookDest := validation.Map(
	validation.Key("type", validation.Required, validation.In("webhook")),
	validation.Key("url", validation.Required, is.URL),
	// A union nested on a single field: the secret may be null, OR a string of
	// 16-64 chars. The key is optional, so absent / null / value all pass.
	validation.Key("secret", validation.OneOf(
		validation.Nil,
		validation.AllOf(is.String, validation.Length(16, 64)),
	)).Required(false),
)
smsDest := validation.Map(
	validation.Key("type", validation.Required, validation.In("sms")),
	validation.Key("phone", validation.Required, is.E164),
)

// The outer union picks the shape. .Strict() guards against an input that
// somehow satisfies more than one shape at once.
destination := validation.OneOf(emailDest, webhookDest, smsDest).Strict()

err := validation.Validate(input, destination)

AllOf is also handy wrapping a OneOf rather than inside one, to gate a union behind a coarse type check. Asserting the structural type first means a value of the wrong type gets one clean "must be an object" error instead of a oneOf array of every shape it failed to be:

err := validation.Validate(input, validation.AllOf(
	is.Map, // first prove it is an object at all,
	validation.OneOf(emailDest, webhookDest, smsDest), // then that it is one of the shapes.
))

The errors nest the same way the rules do: a failed inner OneOf produces a OneOfError that sits inside the outer OneOfError's oneOf array (or inside a parent validation.Errors when the union is one field of a larger object), so a nested structure serializes to nested JSON rather than a flattened string. See the next section for the exact shape.

The error shape

A failed union produces a OneOfError, which marshals to JSON as a single oneOf field whose value is an array of the per-variant error maps, one entry per schema, in order. Each entry contains the fields that failed for that variant:

b, _ := json.Marshal(err)
fmt.Println(string(b))
// {"oneOf":[{"username":"must not be provided"},{"email":"must not be provided"}]}

Because OneOfError is returned unwrapped, it nests correctly inside a parent validation.Errors (for example when a union is one field of a larger object), serializing structurally rather than collapsing to a string.

Validation Errors

The validation.ValidateStruct method returns validation errors found in struct fields in terms of validation.Errors which is a map of fields and their corresponding errors. Nil is returned if validation passes.

By default, validation.Errors uses the struct tags named json to determine what names should be used to represent the invalid fields. The type also implements the json.Marshaler interface so that it can be marshaled into a proper JSON object. For example,

type Address struct {
	Street string `json:"street"`
	City   string `json:"city"`
	State  string `json:"state"`
	Zip    string `json:"zip"`
}

// ...perform validation here...

err := a.Validate()
b, _ := json.Marshal(err)
fmt.Println(string(b))
// Output:
// {"street":"the length must be between 5 and 50","state":"must be in a valid format"}

You may modify validation.ErrorTag to use a different struct tag name.

If you do not like the magic that ValidateStruct determines error keys based on struct field names or corresponding tag values, you may use the following alternative approach:

c := Customer{
	Name:  "Qiang Xue",
	Email: "q",
	Address: Address{
		State:  "Virginia",
	},
}

err := validation.Errors{
	"name": validation.Validate(c.Name, validation.Required, validation.Length(5, 20)),
	"email": validation.Validate(c.Name, validation.Required, is.Email),
	"zip": validation.Validate(c.Address.Zip, validation.Required, validation.Match(regexp.MustCompile("^[0-9]{5}$"))),
}.Filter()
fmt.Println(err)
// Output:
// email: must be a valid email address; zip: cannot be blank.

In the above example, we build a validation.Errors by a list of names and the corresponding validation results. At the end we call Errors.Filter() to remove from Errors all nils which correspond to those successful validation results. The method will return nil if Errors is empty.

The above approach is very flexible as it allows you to freely build up your validation error structure. You can use it to validate both struct and non-struct values. Compared to using ValidateStruct to validate a struct, it has the drawback that you have to redundantly specify the error keys while ValidateStruct can automatically find them out.

Internal Errors

Internal errors are different from validation errors in that internal errors are caused by malfunctioning code (e.g. a validator making a remote call to validate some data when the remote service is down) rather than the data being validated. When an internal error happens during data validation, you may allow the user to resubmit the same data to perform validation again, hoping the program resumes functioning. On the other hand, if data validation fails due to data error, the user should generally not resubmit the same data again.

To differentiate internal errors from validation errors, when an internal error occurs in a validator, wrap it into validation.InternalError by calling validation.NewInternalError(). The user of the validator can then check if a returned error is an internal error or not. For example,

if err := a.Validate(); err != nil {
	if e, ok := err.(validation.InternalError); ok {
		// an internal error happened
		fmt.Println(e.InternalError())
	}
}

Validatable Types

A type is validatable if it implements the validation.Validatable interface.

When validation.Validate is used to validate a validatable value, if it does not find any error with the given validation rules, it will further call the value's Validate() method.

Similarly, when validation.ValidateStruct is validating a struct field whose type is validatable, it will call the field's Validate method after it passes the listed rules.

Note: When implementing validation.Validatable, do not call validation.Validate() to validate the value in its original type because this will cause infinite loops. For example, if you define a new type MyString as string and implement validation.Validatable for MyString, within the Validate() function you should cast the value to string first before calling validation.Validate() to validate it.

In the following example, the Address field of Customer is validatable because Address implements validation.Validatable. Therefore, when validating a Customer struct with validation.ValidateStruct, validation will "dive" into the Address field.

type Customer struct {
	Name    string
	Gender  string
	Email   string
	Address Address
}

func (c Customer) Validate() error {
	return validation.ValidateStruct(&c,
		// Name cannot be empty, and the length must be between 5 and 20.
		validation.Field(&c.Name, validation.Required, validation.Length(5, 20)),
		// Gender is optional, and should be either "Female" or "Male".
		validation.Field(&c.Gender, validation.In("Female", "Male")),
		// Email cannot be empty and should be in a valid email format.
		validation.Field(&c.Email, validation.Required, is.Email),
		// Validate Address using its own validation rules
		validation.Field(&c.Address),
	)
}

c := Customer{
	Name:  "Qiang Xue",
	Email: "q",
	Address: Address{
		Street: "123 Main Street",
		City:   "Unknown",
		State:  "Virginia",
		Zip:    "12345",
	},
}

err := c.Validate()
fmt.Println(err)
// Output:
// Address: (State: must be in a valid format.); Email: must be a valid email address.

Sometimes, you may want to skip the invocation of a type's Validate method. To do so, simply associate a validation.Skip rule with the value being validated.

Maps/Slices/Arrays of Validatables

When validating an iterable (map, slice, or array), whose element type implements the validation.Validatable interface, the validation.Validate method will call the Validate method of every non-nil element. The validation errors of the elements will be returned as validation.Errors which maps the keys of the invalid elements to their corresponding validation errors. For example,

addresses := []Address{
	Address{State: "MD", Zip: "12345"},
	Address{Street: "123 Main St", City: "Vienna", State: "VA", Zip: "12345"},
	Address{City: "Unknown", State: "NC", Zip: "123"},
}
err := validation.Validate(addresses)
fmt.Println(err)
// Output:
// 0: (City: cannot be blank; Street: cannot be blank.); 2: (Street: cannot be blank; Zip: must be in a valid format.).

When using validation.ValidateStruct to validate a struct, the above validation procedure also applies to those struct fields which are map/slices/arrays of validatables.

Each

The Each validation rule allows you to apply a set of rules to each element of an array, slice, or map.

type Customer struct {
    Name      string
    Emails    []string
}

func (c Customer) Validate() error {
    return validation.ValidateStruct(&c,
        // Name cannot be empty, and the length must be between 5 and 20.
		validation.Field(&c.Name, validation.Required, validation.Length(5, 20)),
		// Emails are optional, but if given must be valid.
		validation.Field(&c.Emails, validation.Each(is.Email)),
    )
}

c := Customer{
    Name:   "Qiang Xue",
    Emails: []Email{
        "valid@example.com",
        "invalid",
    },
}

err := c.Validate()
fmt.Println(err)
// Output:
// Emails: (1: must be a valid email address.).
Pointers

When a value being validated is a pointer, most validation rules will validate the actual value pointed to by the pointer. If the pointer is nil, these rules will skip the validation.

An exception is the validation.Required and validation.NotNil rules. When a pointer is nil, they will report a validation error.

Types Implementing sql.Valuer

If a data type implements the sql.Valuer interface (e.g. sql.NullString), the built-in validation rules will handle it properly. In particular, when a rule is validating such data, it will call the Value() method and validate the returned value instead.

Required vs. Not Nil

When validating input values, there are two different scenarios about checking if input values are provided or not.

In the first scenario, an input value is considered missing if it is not entered or it is entered as a zero value (e.g. an empty string, a zero integer). You can use the validation.Required rule in this case.

In the second scenario, an input value is considered missing only if it is not entered. A pointer field is usually used in this case so that you can detect if a value is entered or not by checking if the pointer is nil or not. You can use the validation.NotNil rule to ensure a value is entered (even if it is a zero value).

Presence and nullability are two different questions

"Required" tends to get used as a single knob, but for JSON input there are really two independent questions, and it helps to keep them apart:

  • Presence — is the field in the payload at all? ({"x": ...} vs {})
  • Nullability — if it is present, may its value be null? ({"x": null} vs {"x": <value>})

These are orthogonal, so crossing them gives four states, not three:

null not allowed null allowed
must be present required, non-nullable (the classic "required") required but nullable
may be absent optional, but not null if present optional and nullable

The rules line up with the two axes like this:

  • Presence is handled by the Map machinery: validation.Key("x").Required(true) reports a missing key as "required key is missing", and .Required(false) lets the key be absent. (Required is the default, so a Key you do not call .Required(false) on must be present.)
  • Nullability is a value rule: validation.NotNil forbids a null value ("must not be nil") and validation.Nil requires one ("must be nil").
  • validation.Required is a third, separate thing — it rejects the zero value (empty string, 0, ...), not just null. Reach for NotNil when you only care about null, and Required when an empty value is also "missing".

So all four states are expressible against a map:

schema := validation.Map(
	// required, non-nullable: must be present AND not null.
	validation.Key("a", validation.NotNil).Required(true),
	// required but nullable: must be present, null is fine.
	validation.Key("b").Required(true),
	// optional, but not null if present.
	validation.Key("c", validation.NotNil).Required(false),
	// optional and nullable: present-null, present-value, or absent all pass.
	validation.Key("d").Required(false),
)
PATCH endpoints (absent vs null)

The reason this distinction matters in practice is partial updates. In a PATCH the three input states usually carry three different meanings:

  • field absent -> leave it alone,
  • field null -> clear it,
  • field present with a value -> set it to that value.

A plain Go struct cannot tell absent from null: encoding/json decodes both {} and {"name": null} into the same zero value (or the same nil pointer), so the distinction is gone before any rule runs. Decoding the body into a map[string]any keeps it — the key is simply not in the map when it was absent. For example, a profile patch where name may be updated but never cleared, while nickname may be updated or cleared:

patch := validation.Map(
	// "name" is optional (absent -> leave alone), but if you do send it, it
	// must be a real non-null value, you cannot null out the name.
	validation.Key("name", validation.NotNil, validation.Length(1, 250)).Required(false),
	// "nickname" is optional too, and it IS nullable: send null to clear it, or
	// a string to set it. Absent still means leave alone.
	validation.Key("nickname", validation.Length(1, 250)).Required(false),
)

Length (like the other value rules) treats a null as valid and skips it, so on nickname it only constrains a present, non-null string while still letting null through to mean "clear". NotNil on name is what rejects an explicit null there. Your handler then branches on which keys are actually present in the map:

if v, ok := body["name"]; ok {
	// Present, and NotNil already guaranteed it is not nil -> set it.
	account.Name = v.(string)
}
if v, ok := body["nickname"]; ok {
	// Present: nil means clear, a value means set.
	if v == nil {
		account.Nickname = nil
	} else {
		s := v.(string)
		account.Nickname = &s
	}
}
// Keys that are not in the map were absent, so they are left untouched.

If you only ever need "absent vs present" and a meaningful null is not a case you care about, a struct of pointer fields with NotNil is simpler — the distinction you give up (null vs absent) is one you would not be acting on anyway.

Embedded Structs

The validation.ValidateStruct method will properly validate a struct that contains embedded structs. In particular, the fields of an embedded struct are treated as if they belong directly to the containing struct. For example,

type Employee struct {
	Name string
}

type Manager struct {
	Employee
	Level int
}

m := Manager{}
err := validation.ValidateStruct(&m,
	validation.Field(&m.Name, validation.Required),
	validation.Field(&m.Level, validation.Required),
)
fmt.Println(err)
// Output:
// Level: cannot be blank; Name: cannot be blank.

In the above code, we use &m.Name to specify the validation of the Name field of the embedded struct Employee. And the validation error uses Name as the key for the error associated with the Name field as if Name a field directly belonging to Manager.

If Employee implements the validation.Validatable interface, we can also use the following code to validate Manager, which generates the same validation result:

func (e Employee) Validate() error {
	return validation.ValidateStruct(&e,
		validation.Field(&e.Name, validation.Required),
	)
}

err := validation.ValidateStruct(&m,
	validation.Field(&m.Employee),
	validation.Field(&m.Level, validation.Required),
)
fmt.Println(err)
// Output:
// Level: cannot be blank; Name: cannot be blank.
Conditional Validation

Sometimes, we may want to validate a value only when certain condition is met. For example, we want to ensure the unit struct field is not empty only when the quantity field is not empty; or we may want to ensure either email or phone is provided. The so-called conditional validation can be achieved with the help of validation.When. The following code implements the aforementioned examples:

result := validation.ValidateStruct(&a,
    validation.Field(&a.Unit, validation.When(a.Quantity != "", validation.Required).Else(validation.Nil)),
    validation.Field(&a.Phone, validation.When(a.Email == "", validation.Required.Error('Either phone or Email is required.')),
    validation.Field(&a.Email, validation.When(a.Phone == "", validation.Required.Error('Either phone or Email is required.')),
)

Note that validation.When and validation.When.Else can take a list of validation rules. These rules will be executed only when the condition is true (When) or false (Else).

The above code can also be simplified using the shortcut validation.Required.When:

result := validation.ValidateStruct(&a,
    validation.Field(&a.Unit, validation.Required.When(a.Quantity != ""), validation.Nil.When(a.Quantity == "")),
    validation.Field(&a.Phone, validation.Required.When(a.Email == "").Error('Either phone or Email is required.')),
    validation.Field(&a.Email, validation.Required.When(a.Phone == "").Error('Either phone or Email is required.')),
)
Comparing Two Fields

Eq and NotEq compare a value against a constant. To compare one struct field against another (for example a password and its confirmation), use EqField/NotEqField and pass a pointer to the sibling field, just like you pass field pointers to Field:

type Registration struct {
	Password        string
	ConfirmPassword string
}

func (r Registration) Validate() error {
	return validation.ValidateStruct(&r,
		validation.Field(&r.Password, validation.Required, validation.Length(8, 100)),
		validation.Field(&r.ConfirmPassword, validation.EqField(&r.Password)),
	)
}

r := Registration{Password: "hunter2!!", ConfirmPassword: "typo"}
fmt.Println(r.Validate())
// Output:
// ConfirmPassword: must be equal to the other value.
Customizing Error Messages

All built-in validation rules allow you to customize their error messages. To do so, simply call the Error() method of the rules. For example,

data := "2123"
err := validation.Validate(data,
	validation.Required.Error("is required"),
	validation.Match(regexp.MustCompile("^[0-9]{5}$")).Error("must be a string with five digits"),
)
fmt.Println(err)
// Output:
// must be a string with five digits

You can also customize the pre-defined error(s) of a built-in rule such that the customization applies to every instance of the rule. For example, the Required rule uses the pre-defined error ErrRequired. You can customize it during the application initialization:

validation.ErrRequired = validation.ErrRequired.SetMessage("the value is required") 
Error Code and Message Translation

The errors returned by the validation rules implement the Error interface which contains the Code() method to provide the error code information. While the message of a validation error is often customized, the code is immutable. You can use error code to programmatically check a validation error or look for the translation of the corresponding message.

If you are developing your own validation rules, you can use validation.NewError() to create a validation error which implements the aforementioned Error interface.

Creating Custom Rules

Creating a custom rule is as simple as implementing the validation.Rule interface. The interface contains a single method as shown below, which should validate the value and return the validation error, if any:

// Validate validates a value and returns an error if validation fails.
Validate(value any) error

If you already have a function with the same signature as shown above, you can call validation.By() to turn it into a validation rule. For example,

func checkAbc(value interface{}) error {
	s, _ := value.(string)
	if s != "abc" {
		return errors.New("must be abc")
	}
	return nil
}

err := validation.Validate("xyz", validation.By(checkAbc))
fmt.Println(err)
// Output: must be abc

If your validation function takes additional parameters, you can use the following closure trick:

func stringEquals(str string) validation.RuleFunc {
	return func(value interface{}) error {
		s, _ := value.(string)
        if s != str {
            return errors.New("unexpected string")
        }
        return nil
    }
}

err := validation.Validate("xyz", validation.By(stringEquals("abc")))
fmt.Println(err)
// Output: unexpected string
Rule Groups

When a combination of several rules are used in multiple places, you may use the following trick to create a rule group so that your code is more maintainable.

var NameRule = []validation.Rule{
	validation.Required,
	validation.Length(5, 20),
}

type User struct {
	FirstName string
	LastName  string
}

func (u User) Validate() error {
	return validation.ValidateStruct(&u,
		validation.Field(&u.FirstName, NameRule...),
		validation.Field(&u.LastName, NameRule...),
	)
}

In the above example, we create a rule group NameRule which consists of two validation rules. We then use this rule group to validate both FirstName and LastName.

Context-aware Validation

While most validation rules are self-contained, some rules may depend dynamically on a context. A rule may implement the validation.RuleWithContext interface to support the so-called context-aware validation.

To validate an arbitrary value with a context, call validation.ValidateWithContext(). The context.Conext parameter will be passed along to those rules that implement validation.RuleWithContext.

To validate the fields of a struct with a context, call validation.ValidateStructWithContext().

You can define a context-aware rule from scratch by implementing both validation.Rule and validation.RuleWithContext. You can also use validation.WithContext() to turn a function into a context-aware rule. For example,

rule := validation.WithContext(func(ctx context.Context, value interface{}) error {
	if ctx.Value("secret") == value.(string) {
	    return nil
	}
	return errors.New("value incorrect")
})
value := "xyz"
ctx := context.WithValue(context.Background(), "secret", "example")
err := validation.ValidateWithContext(ctx, value, rule)
fmt.Println(err)
// Output: value incorrect

When performing context-aware validation, if a rule does not implement validation.RuleWithContext, its validation.Rule will be used instead.

Built-in Validation Rules

The following rules are provided in the validation package:

Many of these rules are generic. The generic type parameter is usually inferred from the argument, so you can write validation.In("a", "b") or validation.Min(10) without spelling it out.

Equality and membership

  • Eq[T any](expected T): checks if a value is equal to expected (using reflect.DeepEqual).
  • NotEq[T any](forbidden T): checks if a value is NOT equal to forbidden.
  • EqField[T any](other *T): checks if a value equals the field pointed to by other. Intended for comparing two struct fields, e.g. a password and its confirmation. Pass a pointer to the sibling field the same way you pass it to Field.
  • NotEqField[T any](other *T): checks if a value differs from the field pointed to by other, e.g. a new password that must not match the current one.
  • In[T any](...T): checks if a value can be found in the given list of values.
  • NotIn[T any](...T): checks if a value is NOT among the given list of values.

Numeric and ordered comparisons

  • Min[T Threshold](min T) and Max[T Threshold](max T): checks if a value is within the specified bound (inclusive). Call .Exclusive() to make the bound strict. Supports int, uint, float and time.Time.
  • Gt[T Threshold](min T), Gte[T Threshold](min T), Lt[T Threshold](max T), Lte[T Threshold](max T): readable shorthands for strict/inclusive greater-than and less-than comparisons. Gt is equivalent to Min(min).Exclusive(), Gte to Min(min), and likewise for Lt/Lte and Max.
  • Between[T Threshold](min, max T): checks if a value is within the inclusive range [min, max]. Call .Exclusive() to exclude both boundaries.
  • MultipleOf[T Integer](base T): checks if a value is a multiple of base.

Strings

  • Length(min, max int): checks if the length of a value is within the specified range. This rule should only be used for validating strings, slices, maps, and arrays.
  • RuneLength(min, max int): checks if the length of a string is within the specified range. This rule is similar as Length except that when the value being validated is a string, it checks its rune length instead of byte length.
  • Match(*regexp.Regexp): checks if a value matches the specified regular expression. This rule should only be used for strings and byte slices.
  • HasPrefix(prefix string): checks if a string starts with prefix.
  • HasSuffix(suffix string): checks if a string ends with suffix.
  • Contains(substring string): checks if a string contains substring.
  • Date(layout string): checks if a string value is a date whose format is specified by the layout. By calling Min() and/or Max(), you can check additionally if the date is within the specified range.

Presence

  • Required: checks if a value is not empty (neither nil nor zero).
  • NotNil: checks if a pointer value is not nil. Non-pointer values are considered valid.
  • NilOrNotEmpty: checks if a value is a nil pointer or a non-empty value. This differs from Required in that it treats a nil pointer as valid.
  • Nil: checks if a value is a nil pointer.
  • Empty: checks if a value is empty. nil pointers are considered valid.
  • Never: checks that a value is absent — a nil pointer/interface, or the zero value for any other type. Use it on the struct fields that a discriminated-union variant forbids (the counterpart to Required). Unlike Empty, a present pointer fails even when it references an empty value.

Composition and control flow

  • Each(rules ...Rule): checks the elements within an iterable (map/slice/array) with other rules.
  • When(condition, rules ...Rule): validates with the specified rules only when the condition is true.
  • Else(rules ...Rule): must be used with When(condition, rules ...Rule), validates with the specified rules only when the condition is false.
  • Skip: this is a special rule used to indicate that all rules following it should be skipped (including the nested ones).

Unions (one-of)

  • OneOf(schemas ...Rule): passes when the value matches at least one of the schemas (the first match wins). Call .Strict() to require exactly one match. On failure the error is a OneOfError that marshals to {"oneOf": [...]}.
  • AllOf(rules ...Rule): passes only when the value matches every one of the rules (the AND counterpart to OneOf). Its main use is bundling several rules into one so a whole SET of rules can be a single branch of a OneOf. Stops at the first failing rule.
  • MatchOneOf(value, schemas ...Rule) (int, error) / MatchOneOfWithContext: like OneOf but returns the index of the matching schema so you can act on the matched shape. Schemas are typically Map(...) rules; a variant forbids a key by omitting it.
  • MatchOneOfStruct[T](ctx, *T, schemas ...[]*FieldRules) (int, error): the struct counterpart, taking one []*FieldRules per variant. Use Never to forbid the fields a variant disallows.

The is sub-package provides a list of commonly used string validation rules that can be used to check if the format of a value satisfies certain requirements. Note that these rules only handle strings and byte slices and if a string or byte slice is empty, it is considered valid. You may use a Required rule to ensure a value is not empty. Below is the whole list of the rules provided by the is package:

  • Email: validates if a string is an email or not. It also checks if the MX record exists for the email domain.
  • EmailFormat: validates if a string is an email or not. It does NOT check the existence of the MX record.
  • URL: validates if a string is a valid URL
  • RequestURL: validates if a string is a valid request URL
  • RequestURI: validates if a string is a valid request URI
  • Alpha: validates if a string contains English letters only (a-zA-Z)
  • Digit: validates if a string contains digits only (0-9)
  • Alphanumeric: validates if a string contains English letters and digits only (a-zA-Z0-9)
  • UTFLetter: validates if a string contains unicode letters only
  • UTFDigit: validates if a string contains unicode decimal digits only
  • UTFLetterNumeric: validates if a string contains unicode letters and numbers only
  • UTFNumeric: validates if a string contains unicode number characters (category N) only
  • LowerCase: validates if a string contains lower case unicode letters only
  • UpperCase: validates if a string contains upper case unicode letters only
  • Hexadecimal: validates if a string is a valid hexadecimal number
  • HexColor: validates if a string is a valid hexadecimal color code
  • RGBColor: validates if a string is a valid RGB color in the form of rgb(R, G, B)
  • Int: validates if a string is a valid integer number
  • Float: validates if a string is a floating point number
  • UUIDv3: validates if a string is a valid version 3 UUID
  • UUIDv4: validates if a string is a valid version 4 UUID
  • UUIDv5: validates if a string is a valid version 5 UUID
  • UUID: validates if a string is a valid UUID
  • CreditCard: validates if a string is a valid credit card number
  • ISBN10: validates if a string is an ISBN version 10
  • ISBN13: validates if a string is an ISBN version 13
  • ISBN: validates if a string is an ISBN (either version 10 or 13)
  • JSON: validates if a string is in valid JSON format
  • ASCII: validates if a string contains ASCII characters only
  • PrintableASCII: validates if a string contains printable ASCII characters only
  • PrintableUnicode: validates if a string contains printable characters only (via unicode.IsPrint), allowing international text and emoji while rejecting tabs, newlines, and invisible characters
  • Multibyte: validates if a string contains multibyte characters
  • FullWidth: validates if a string contains full-width characters
  • HalfWidth: validates if a string contains half-width characters
  • VariableWidth: validates if a string contains both full-width and half-width characters
  • Base64: validates if a string is encoded in Base64
  • Base32: validates if a string is encoded in Base32
  • DataURI: validates if a string is a valid base64-encoded data URI
  • E164: validates if a string is a valid E164 phone number (+19251232233)
  • CountryCode2: validates if a string is a valid ISO3166 Alpha 2 country code
  • CountryCode3: validates if a string is a valid ISO3166 Alpha 3 country code
  • DialString: validates if a string is a valid dial string that can be passed to Dial()
  • MAC: validates if a string is a MAC address
  • IP: validates if a string is a valid IP address (either version 4 or 6)
  • IPv4: validates if a string is a valid version 4 IP address
  • IPv6: validates if a string is a valid version 6 IP address
  • Subdomain: validates if a string is valid subdomain
  • Domain: validates if a string is valid domain
  • DNSName: validates if a string is valid DNS name
  • Host: validates if a string is a valid IP (both v4 and v6) or a valid DNS name
  • Port: validates if a string is a valid port number
  • MongoID: validates if a string is a valid Mongo ID
  • Latitude: validates if a string is a valid latitude
  • Longitude: validates if a string is a valid longitude
  • SSN: validates if a string is a social security number (SSN)
  • Semver: validates if a string is a valid semantic version

Credits

The is sub-package wraps the excellent validators provided by the govalidator package.

Documentation

Overview

Package validation provides configurable and extensible rules for validating data of various types.

Example
package main

import (
	"fmt"
	"regexp"

	"github.com/monetr/validation"
	"github.com/monetr/validation/is"
)

type Address struct {
	Street string
	City   string
	State  string
	Zip    string
}

type Customer struct {
	Name    string
	Gender  string
	Email   string
	Address Address
}

func (a Address) Validate() error {
	return validation.ValidateStruct(&a,

		validation.Field(&a.Street, validation.Required, validation.Length(5, 50)),

		validation.Field(&a.City, validation.Required, validation.Length(5, 50)),

		validation.Field(&a.State, validation.Required, validation.Match(regexp.MustCompile("^[A-Z]{2}$"))),

		validation.Field(&a.Zip, validation.Required, validation.Match(regexp.MustCompile("^[0-9]{5}$"))),
	)
}

func (c Customer) Validate() error {
	return validation.ValidateStruct(&c,

		validation.Field(&c.Name, validation.Required, validation.Length(5, 20)),

		validation.Field(&c.Gender, validation.In("Female", "Male")),

		validation.Field(&c.Email, validation.Required, is.Email),

		validation.Field(&c.Address),
	)
}

func main() {
	c := Customer{
		Name:  "Qiang Xue",
		Email: "q",
		Address: Address{
			Street: "123 Main Street",
			City:   "Unknown",
			State:  "Virginia",
			Zip:    "12345",
		},
	}

	err := c.Validate()
	fmt.Println(err)
}
Output:
Address: (State: must be in a valid format.); Email: must be a valid email address.
Example (Five)
package main

import (
	"fmt"

	"github.com/monetr/validation"
)

func main() {
	type Employee struct {
		Name string
	}

	type Manager struct {
		Employee
		Level int
	}

	m := Manager{}
	err := validation.ValidateStruct(&m,
		validation.Field(&m.Name, validation.Required),
		validation.Field(&m.Level, validation.Required),
	)
	fmt.Println(err)
}
Output:
Level: cannot be blank; Name: cannot be blank.
Example (Four)
package main

import (
	"fmt"
	"regexp"

	"github.com/monetr/validation"
	"github.com/monetr/validation/is"
)

type Address struct {
	Street string
	City   string
	State  string
	Zip    string
}

type Customer struct {
	Name    string
	Gender  string
	Email   string
	Address Address
}

func (a Address) Validate() error {
	return validation.ValidateStruct(&a,

		validation.Field(&a.Street, validation.Required, validation.Length(5, 50)),

		validation.Field(&a.City, validation.Required, validation.Length(5, 50)),

		validation.Field(&a.State, validation.Required, validation.Match(regexp.MustCompile("^[A-Z]{2}$"))),

		validation.Field(&a.Zip, validation.Required, validation.Match(regexp.MustCompile("^[0-9]{5}$"))),
	)
}

func (c Customer) Validate() error {
	return validation.ValidateStruct(&c,

		validation.Field(&c.Name, validation.Required, validation.Length(5, 20)),

		validation.Field(&c.Gender, validation.In("Female", "Male")),

		validation.Field(&c.Email, validation.Required, is.Email),

		validation.Field(&c.Address),
	)
}

func main() {
	c := Customer{
		Name:  "Qiang Xue",
		Email: "q",
		Address: Address{
			State: "Virginia",
		},
	}

	err := validation.Errors{
		"name":  validation.Validate(c.Name, validation.Required, validation.Length(5, 20)),
		"email": validation.Validate(c.Name, validation.Required, is.Email),
		"zip":   validation.Validate(c.Address.Zip, validation.Required, validation.Match(regexp.MustCompile("^[0-9]{5}$"))),
	}.Filter()
	fmt.Println(err)
}
Output:
email: must be a valid email address; zip: cannot be blank.
Example (Second)
package main

import (
	"fmt"

	"github.com/monetr/validation"
	"github.com/monetr/validation/is"
)

func main() {
	data := "example"
	err := validation.Validate(data,
		validation.Required,       // not empty
		validation.Length(5, 100), // length between 5 and 100
		is.URL,                    // is a valid URL
	)
	fmt.Println(err)
}
Output:
must be a valid URL
Example (Seven)
package main

import (
	"fmt"
	"regexp"

	"github.com/monetr/validation"
	"github.com/monetr/validation/is"
)

func main() {
	c := map[string]interface{}{
		"Name":  "Qiang Xue",
		"Email": "q",
		"Address": map[string]interface{}{
			"Street": "123",
			"City":   "Unknown",
			"State":  "Virginia",
			"Zip":    "12345",
		},
	}

	err := validation.Validate(c,
		validation.Map(
			// Name cannot be empty, and the length must be between 5 and 20.
			validation.Key("Name", validation.Required, validation.Length(5, 20)),
			// Email cannot be empty and should be in a valid email format.
			validation.Key("Email", validation.Required, is.Email),
			// Validate Address using its own validation rules
			validation.Key("Address", validation.Map(
				// Street cannot be empty, and the length must between 5 and 50
				validation.Key("Street", validation.Required, validation.Length(5, 50)),
				// City cannot be empty, and the length must between 5 and 50
				validation.Key("City", validation.Required, validation.Length(5, 50)),
				// State cannot be empty, and must be a string consisting of two letters in upper case
				validation.Key("State", validation.Required, validation.Match(regexp.MustCompile("^[A-Z]{2}$"))),
				// State cannot be empty, and must be a string consisting of five digits
				validation.Key("Zip", validation.Required, validation.Match(regexp.MustCompile("^[0-9]{5}$"))),
			)),
		),
	)
	fmt.Println(err)
}
Output:
Address: (State: must be in a valid format; Street: the length must be between 5 and 50.); Email: must be a valid email address.
Example (Six)
package main

import (
	"context"
	"errors"
	"fmt"

	"github.com/monetr/validation"
)

type contextKey int

func main() {
	key := contextKey(1)
	rule := validation.WithContext(func(ctx context.Context, value interface{}) error {
		s, _ := value.(string)
		if ctx.Value(key) == s {
			return nil
		}
		return errors.New("unexpected value")
	})
	ctx := context.WithValue(context.Background(), key, "good sample")

	err1 := validation.ValidateWithContext(ctx, "bad sample", rule)
	fmt.Println(err1)

	err2 := validation.ValidateWithContext(ctx, "good sample", rule)
	fmt.Println(err2)

}
Output:
unexpected value
<nil>
Example (Third)
package main

import (
	"fmt"
	"regexp"

	"github.com/monetr/validation"
)

type Address struct {
	Street string
	City   string
	State  string
	Zip    string
}

func (a Address) Validate() error {
	return validation.ValidateStruct(&a,

		validation.Field(&a.Street, validation.Required, validation.Length(5, 50)),

		validation.Field(&a.City, validation.Required, validation.Length(5, 50)),

		validation.Field(&a.State, validation.Required, validation.Match(regexp.MustCompile("^[A-Z]{2}$"))),

		validation.Field(&a.Zip, validation.Required, validation.Match(regexp.MustCompile("^[0-9]{5}$"))),
	)
}

func main() {
	addresses := []Address{
		{State: "MD", Zip: "12345"},
		{Street: "123 Main St", City: "Vienna", State: "VA", Zip: "12345"},
		{City: "Unknown", State: "NC", Zip: "123"},
	}
	err := validation.Validate(addresses)
	fmt.Println(err)
}
Output:
0: (City: cannot be blank; Street: cannot be blank.); 2: (Street: cannot be blank; Zip: must be in a valid format.).

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrNil is the error that returns when a value is not nil.
	ErrNil = NewError("validation_nil", "must be nil")
	// ErrEmpty is the error that returns when a not nil value is not empty.
	ErrEmpty = NewError("validation_empty", "must be blank")
)
View Source
var (
	// ErrDateInvalid is the error that returns in case of an invalid date.
	ErrDateInvalid = NewError("validation_date_invalid", "must be a valid date")
	// ErrDateOutOfRange is the error that returns in case of an invalid date.
	ErrDateOutOfRange = NewError("validation_date_out_of_range", "the date is out of range")
)
View Source
var (
	// ErrLengthTooLong is the error that returns in case of too long length.
	ErrLengthTooLong = NewError("validation_length_too_long", "the length must be no more than {{.max}}")
	// ErrLengthTooShort is the error that returns in case of too short length.
	ErrLengthTooShort = NewError("validation_length_too_short", "the length must be no less than {{.min}}")
	// ErrLengthInvalid is the error that returns in case of an invalid length.
	ErrLengthInvalid = NewError("validation_length_invalid", "the length must be exactly {{.min}}")
	// ErrLengthOutOfRange is the error that returns in case of out of range length.
	ErrLengthOutOfRange = NewError("validation_length_out_of_range", "the length must be between {{.min}} and {{.max}}")
	// ErrLengthEmptyRequired is the error that returns in case of non-empty value.
	ErrLengthEmptyRequired = NewError("validation_length_empty_required", "the value must be empty")
)
View Source
var (
	// ErrNotMap is the error that the value being validated is not a map.
	ErrNotMap = errors.New("only a map can be validated")

	// ErrKeyWrongType is the error returned in case of an incorrect key type.
	ErrKeyWrongType = NewError("validation_key_wrong_type", "key not the correct type")

	// ErrKeyMissing is the error returned in case of a missing key.
	ErrKeyMissing = NewError("validation_key_missing", "required key is missing")

	// ErrKeyUnexpected is the error returned in case of an unexpected key.
	ErrKeyUnexpected = NewError("validation_key_unexpected", "key not expected")
)
View Source
var (
	// ErrMinGreaterEqualThanRequired is the error that returns when a value is less than a specified threshold.
	ErrMinGreaterEqualThanRequired = NewError("validation_min_greater_equal_than_required", "must be no less than {{.threshold}}")
	// ErrMaxLessEqualThanRequired is the error that returns when a value is greater than a specified threshold.
	ErrMaxLessEqualThanRequired = NewError("validation_max_less_equal_than_required", "must be no greater than {{.threshold}}")
	// ErrMinGreaterThanRequired is the error that returns when a value is less than or equal to a specified threshold.
	ErrMinGreaterThanRequired = NewError("validation_min_greater_than_required", "must be greater than {{.threshold}}")
	// ErrMaxLessThanRequired is the error that returns when a value is greater than or equal to a specified threshold.
	ErrMaxLessThanRequired = NewError("validation_max_less_than_required", "must be less than {{.threshold}}")
)
View Source
var (
	// ErrRequired is the error that returns when a value is required.
	ErrRequired = NewError("validation_required", "cannot be blank")
	// ErrNilOrNotEmpty is the error that returns when a value is not nil and is empty.
	ErrNilOrNotEmpty = NewError("validation_nil_or_not_empty_required", "cannot be blank")
)
View Source
var (
	// ErrHasPrefixInvalid is the error that returns when a string does not start with the required prefix.
	ErrHasPrefixInvalid = NewError("validation_has_prefix_invalid", "must start with {{.prefix}}")
	// ErrHasSuffixInvalid is the error that returns when a string does not end with the required suffix.
	ErrHasSuffixInvalid = NewError("validation_has_suffix_invalid", "must end with {{.suffix}}")
	// ErrContainsInvalid is the error that returns when a string does not contain the required substring.
	ErrContainsInvalid = NewError("validation_contains_invalid", "must contain {{.substring}}")
)
View Source
var (
	// ErrTypeString is the error returned when a value is not a string.
	ErrTypeString = NewError("validation_type_string", "must be a string")
	// ErrTypeInteger is the error returned when a value is not an integer.
	ErrTypeInteger = NewError("validation_type_integer", "must be an integer")
	// ErrTypeFloat is the error returned when a value is not a number.
	ErrTypeFloat = NewError("validation_type_float", "must be a number")
	// ErrTypeBool is the error returned when a value is not a boolean.
	ErrTypeBool = NewError("validation_type_bool", "must be a boolean")
	// ErrTypeArray is the error returned when a value is not an array.
	ErrTypeArray = NewError("validation_type_array", "must be an array")
	// ErrTypeMap is the error returned when a value is not an object. The JSON
	// term is used in the message because these rules are meant for JSON decoded
	// data, where a Go map is the object.
	ErrTypeMap = NewError("validation_type_map", "must be an object")
)
View Source
var (
	// Deprecated: Use is.String instead.
	IsString = TypeRule{/* contains filtered or unexported fields */}
	// Deprecated: Use is.Integer instead.
	IsInteger = TypeRule{/* contains filtered or unexported fields */}
	IsFloat   = TypeRule{/* contains filtered or unexported fields */}
	// Deprecated: Use is.Boolean instead.
	IsBoolean = TypeRule{/* contains filtered or unexported fields */}
	// Deprecated: Use is.Array instead.
	IsArray = TypeRule{/* contains filtered or unexported fields */}
	// Deprecated: Use is.Map instead.
	IsMap = TypeRule{/* contains filtered or unexported fields */}
)

IsString, IsInteger, IsFloat, and IsBoolean assert the underlying type of a value. They are intended for values whose static type is dynamic (any) — for example data decoded from JSON into an interface or a map[string]any — where the Go compiler can no longer guarantee the type. When the static type is already concrete there is nothing for these rules to check.

Unlike the value-oriented rules (Length, Match, Min, ...) which dereference to an empty value and treat it as valid, the type rules only skip a nil pointer/interface. A present zero value such as 0, "", or false carries a type, so the rule still asserts it: IsString rejects a present 0, while IsInteger accepts a present 0. Use Required to additionally demand presence.

Numbers are matched by value, not by Go kind, so they behave the same whether JSON was decoded with the default float64 numbers or with json.Decoder's UseNumber:

  • IsFloat accepts any numeric value (integers included — every integer is a valid number).
  • IsInteger accepts any integer-valued number, including a whole-valued float such as 5.0 (but not 5.5). This is required because the default json.Unmarshal turns every number into a float64, so 5 and 5.0 are indistinguishable; IsInteger asserts the value, not how it was spelled.

A json.Number is classified by its textual content for IsInteger/IsFloat. It can only originate from an unquoted JSON number token, never from a quoted string, so it is never a string (nor a boolean): IsString and IsBoolean always reject a json.Number.

IsArray and IsMap assert the two structural JSON types. A JSON array decodes to a slice (the default []any) and a JSON object decodes to a map (the default map[string]any), so those are what these rules accept. IsArray deliberately does NOT accept a []byte: the library treats a byte slice as string content everywhere else (see IsString), so a []byte is a string here, not an array. Like the other type rules they only skip a true nil, which for these includes a nil slice/map, a present but empty []any{} or map[string]any{} still carries its type and so is accepted.

These rules now live in the is package too, where they read more naturally at the call site: is.String instead of validation.IsString. The is package has its own full copy of this logic, the package level rules below are kept so we dont break anyone but theyre deprecated, prefer the is package versions. IsFloat is the odd one out and stays un-deprecated for now because the is package already has an is.Float that checks string contents, so theres no clean name for the type rule over there yet.

View Source
var (
	// ErrorTag is the struct tag name used to customize the error field name for a struct field.
	ErrorTag = "json"

	// Skip is a special validation rule that indicates all rules following it should be skipped.
	Skip = skipRule{/* contains filtered or unexported fields */}
)
View Source
var Empty = absentRule{/* contains filtered or unexported fields */}

Empty checks if a not nil value is empty.

View Source
var ErrAllOfInvalid = NewError("validation_all_of_invalid", "must be in a valid format")

ErrAllOfInvalid is the error a custom-messaged AllOf surfaces when any rule in the set fails. By default AllOf has no error of its own (it just passes the first failing sub-rule's error straight through), so this only comes into play once you set a custom message with AllOfRule.Error.

View Source
var (

	// ErrAmbiguousMatch is returned by a strict union (see [OneOfRule.Strict])
	// when more than one alternative schema validates. It indicates the schemas
	// are not mutually exclusive.
	ErrAmbiguousMatch = NewError(
		"validation_oneof_ambiguous",
		"must match exactly one of the allowed shapes, but matched several",
	)
)
View Source
var ErrBetweenInvalid = NewError("validation_between_invalid", "must be between {{.min}} and {{.max}}")

ErrBetweenInvalid is the error that returns when a value is not within the specified range.

View Source
var ErrEqFieldInvalid = NewError("validation_eq_field_invalid", "must be equal to the other value")

ErrEqFieldInvalid is the error that returns when a value does not match the value of another field.

View Source
var ErrEqInvalid = NewError("validation_eq_invalid", "must be equal to {{.expected}}")

ErrEqInvalid is the error that returns when a value is not equal to the expected value.

View Source
var ErrInInvalid = NewError("validation_in_invalid", "must be a valid value")

ErrInInvalid is the error that returns in case of an invalid value for "in" rule.

View Source
var ErrMatchInvalid = NewError("validation_match_invalid", "must be in a valid format")

ErrMatchInvalid is the error that returns in case of invalid format.

View Source
var ErrMultipleOfInvalid = NewError("validation_multiple_of_invalid", "must be multiple of {{.base}}")

ErrMultipleOfInvalid is the error that returns when a value is not multiple of a base.

View Source
var ErrNever = NewError("validation_never", "must not be provided")

ErrNever is the error returned by Never when a value that must be absent is instead present with a meaningful value.

View Source
var ErrNotEqFieldInvalid = NewError("validation_not_eq_field_invalid", "must not be equal to the other value")

ErrNotEqFieldInvalid is the error that returns when a value matches the value of another field.

View Source
var ErrNotEqInvalid = NewError("validation_not_eq_invalid", "must not be equal to {{.forbidden}}")

ErrNotEqInvalid is the error that returns when a value is equal to the forbidden value.

View Source
var ErrNotInInvalid = NewError("validation_not_in_invalid", "must not be in list")

ErrNotInInvalid is the error that returns when a value is in a list.

View Source
var ErrNotNilRequired = NewError("validation_not_nil_required", "must not be nil")

ErrNotNilRequired is the error that returns when a value is Nil.

View Source
var (
	// ErrStructPointer is the error that a struct being validated is not specified as a pointer.
	ErrStructPointer = errors.New("only a pointer to a struct can be validated")
)
View Source
var Never = neverRule{}

Never is a validation rule that asserts a value is absent. It is the discriminated-union counterpart to Required: use it on the struct fields that a given variant forbids.

A struct field always exists (it is present as its zero value), so Never infers "absent" from the value itself:

  • pointer or interface: must be nil. A non-nil pointer fails even when it references an empty value, because a present pointer is a provided value.
  • any other kind: must be the zero value (empty string, 0, false, empty slice/map/array, the zero time.Time). A meaningful value fails.

This auto-switching is what distinguishes Never from the existing absence rules: Empty dereferences first, so it would let a pointer to an empty value pass, while Nil would reject a non-pointer zero value. Never gives pointers Nil semantics and everything else Empty semantics in one rule.

Never is value-based and intended for struct fields validated with Field. It is deliberately not offered for map keys: a Map schema already reports keys it does not list as ErrKeyUnexpected (unless MapRule.AllowExtraKeys is set), so a map union forbids a key simply by omitting it from the variant that disallows it. Using Never as a map value rule would be a mistake — it would let a present-but-empty value pass when, in a map, the key's mere presence should fail.

View Source
var Nil = absentRule{/* contains filtered or unexported fields */}

Nil is a validation rule that checks if a value is nil. It is the opposite of NotNil rule

View Source
var NilOrNotEmpty = RequiredRule{/* contains filtered or unexported fields */}

NilOrNotEmpty checks if a value is a nil pointer or a value that is not empty. NilOrNotEmpty differs from Required in that it treats a nil pointer as valid.

View Source
var NotNil = notNilRule{}

NotNil is a validation rule that checks if a value is not nil. NotNil only handles types including interface, pointer, slice, and map. All other types are considered valid.

View Source
var Required = RequiredRule{/* contains filtered or unexported fields */}

Required is a validation rule that checks if a value is not empty. A value is considered not empty if - integer, float: not zero - bool: true - string, array, slice, map: len() > 0 - interface, pointer: not nil and the referenced value is not empty - any other types

Functions

func EnsureString

func EnsureString(value interface{}) (string, error)

EnsureString ensures the given value is a string. If the value is a byte slice, it will be typecast into a string. An error is returned otherwise.

func Indirect

func Indirect(value any) (any, bool, error)

Indirect returns the value that the given interface or pointer references to. If the value implements driver.Valuer, it will deal with the value returned by the Value() method instead. A boolean value is also returned to indicate if the value is nil or not (only applicable to interface, pointer, map, and slice). If the value is neither an interface nor a pointer, it will be returned back.

If the value implements driver.Valuer and its Value() method returns an error, that error is returned as an InternalError. A failing Valuer is a malfunction of the data type, not an indication that the value is absent, so it must not be silently treated as a nil (valid) value.

func IsEmpty

func IsEmpty(value interface{}) bool

IsEmpty checks if a value is empty or not. A value is considered empty if - integer, float: zero - bool: false - string, array: len() == 0 - slice, map: nil or len() == 0 - interface, pointer: nil or the referenced value is empty

func LengthOfValue

func LengthOfValue(value interface{}) (int, error)

LengthOfValue returns the length of a value that is a string, slice, map, or array. An error is returned for all other types.

func MatchOneOf added in v1.1.0

func MatchOneOf(value any, schemas ...Rule) (int, error)

MatchOneOf reports the index of the first schema that fully validates value, or (-1, OneOfError) if none do. See MatchOneOfWithContext for the details.

It is named MatchOneOf rather than Match because Match is already the regular-expression rule.

func MatchOneOfStruct added in v1.1.0

func MatchOneOfStruct[T any](
	ctx context.Context,
	structPtr *T,
	schemas ...[]*FieldRules,
) (int, error)

MatchOneOfStruct validates structPtr against several alternative field-rule schemas and returns the index of the first one that fully validates (anyOf semantics — evaluation stops at the first match). When none match it returns -1 and a OneOfError holding each schema's Errors, in order. The returned index lets the caller act on the matched shape, for example to parse or merge it.

MatchOneOfStruct is the struct counterpart to MatchOneOf: a struct schema is a []*FieldRules (as passed to ValidateStruct) rather than a Rule, because field rules are bound to specific struct fields. Use Never within a schema to forbid the fields a variant disallows. A non-validation error from a schema is surfaced directly.

func MatchOneOfWithContext added in v1.1.0

func MatchOneOfWithContext(ctx context.Context, value any, schemas ...Rule) (int, error)

MatchOneOfWithContext validates value against each schema in order and returns the index of the first one that passes. Evaluation stops at the first match (anyOf semantics), so earlier schemas take precedence and the schemas should be written to be mutually exclusive. When no schema matches it returns -1 and a OneOfError holding each schema's failure, in order.

A schema is any Rule; the common case is a MapRule describing one shape of a map. Because a MapRule reports keys it does not list as ErrKeyUnexpected, a map union forbids a field simply by omitting it from the variants that disallow it.

If a schema reports a non-validation problem — an InternalError such as "only a map can be validated" — that error is returned directly rather than recorded as a failed variant, so a configuration bug is never mistaken for a schema mismatch.

func StringOrBytes

func StringOrBytes(value interface{}) (isString bool, str string, isBytes bool, bs []byte)

StringOrBytes typecasts a value into a string or byte slice. Boolean flags are returned to indicate if the typecasting succeeds or not.

func ToFloat

func ToFloat(value interface{}) (float64, error)

ToFloat converts the given value to a float64. An error is returned for all incompatible types.

func ToInt

func ToInt(value interface{}) (int64, error)

ToInt converts the given value to an int64. An error is returned for all incompatible types.

func ToUint

func ToUint(value interface{}) (uint64, error)

ToUint converts the given value to an uint64. An error is returned for all incompatible types.

func Validate

func Validate(value any, rules ...Rule) error

Validate validates the given value and returns the validation error, if any.

Validate performs validation using the following steps:

  1. For each rule, call its `Validate()` to validate the value. Return if any error is found.
  2. If the value being validated implements `Validatable`, call the value's `Validate()`. Return with the validation result.
  3. If the value being validated is a map/slice/array, and the element type implements `Validatable`, for each element call the element value's `Validate()`. Return with the validation result.

func ValidateStruct

func ValidateStruct(structPtr any, fields ...*FieldRules) error

ValidateStruct validates a struct by checking the specified struct fields against the corresponding validation rules. Note that the struct being validated must be specified as a pointer to it. If the pointer is nil, it is considered valid. Use Field() to specify struct fields that need to be validated. Each Field() call specifies a single field which should be specified as a pointer to the field. A field can be associated with multiple rules. For example,

value := struct {
    Name  string
    Value string
}{"name", "demo"}
err := validation.ValidateStruct(&value,
    validation.Field(&a.Name, validation.Required),
    validation.Field(&a.Value, validation.Required, validation.Length(5, 10)),
)
fmt.Println(err)
// Value: the length must be between 5 and 10.

An error will be returned if validation fails.

func ValidateStructWithContext

func ValidateStructWithContext(ctx context.Context, structPtr any, fields ...*FieldRules) error

ValidateStructWithContext validates a struct with the given context. The only difference between ValidateStructWithContext and ValidateStruct is that the former will validate struct fields with the provided context. Please refer to ValidateStruct for the detailed instructions on how to use this function.

func ValidateWithContext

func ValidateWithContext(ctx context.Context, value any, rules ...Rule) error

ValidateWithContext validates the given value with the given context and returns the validation error, if any.

ValidateWithContext performs validation using the following steps:

  1. For each rule, call its `ValidateWithContext()` to validate the value if the rule implements `RuleWithContext`. Otherwise call `Validate()` of the rule. Return if any error is found.
  2. If the value being validated implements `ValidatableWithContext`, call the value's `ValidateWithContext()` and return with the validation result.
  3. If the value being validated implements `Validatable`, call the value's `Validate()` and return with the validation result.
  4. If the value being validated is a map/slice/array, and the element type implements `ValidatableWithContext`, for each element call the element value's `ValidateWithContext()`. Return with the validation result.
  5. If the value being validated is a map/slice/array, and the element type implements `Validatable`, for each element call the element value's `Validate()`. Return with the validation result.

Types

type AllOfRule added in v1.2.0

type AllOfRule struct {
	// contains filtered or unexported fields
}

AllOfRule is the rule produced by AllOf.

func AllOf added in v1.2.0

func AllOf(rules ...Rule) AllOfRule

AllOf bundles several rules into a single Rule that passes only when the value satisfies every one of them. It is the AND counterpart to OneOf's OR.

On its own AllOf is not very interesting, applying a list of rules to a value is what Validate and a field's rule list already do. Its reason to exist is to be one branch of a OneOf: OneOf treats each alternative as a single Rule, so without AllOf there is no way to say "this branch is a whole SET of rules". With it you can express, on a single field, that the value must match one set of rules OR a different set:

validation.Field(&x.Key,
    validation.OneOf(
        validation.Nil,                                            // either it is null,
        validation.AllOf(IsString, validation.Length(10, 64), validation.Match(keyRe)), // OR it is X and Y and Z.
    ),
)

Note the single-rule branch (Nil) does not need AllOf, a lone Rule is already a valid OneOf alternative. AllOf only earns its keep on the branches that are made of more than one rule.

Like Validate, AllOf evaluates its rules in order and stops at the first one that fails, returning that rule's error. So when a OneOf branch built from AllOf fails, the OneOfError records the specific sub-rule that did not pass rather than some merged blob, which I think is the more useful thing to show a client. Skip is honored just as it is everywhere else.

That per-sub-rule error is the right default, but sometimes it is the wrong thing to leak. For a compound validation made of a pile of fiddly rules (an RRULE, a cron expression, some gnarly ID format) the individual sub-rule errors are noise to the client. AllOfRule.Error lets you collapse ANY failure within the set into a single summary message instead, so you can just say "yeah thats not right" and not explain which specific piece tripped.

func (AllOfRule) Error added in v1.3.0

func (r AllOfRule) Error(message string) AllOfRule

Error sets a custom error message for the whole set. Normally AllOf is transparent: when a sub-rule fails its specific error is what bubbles up. Setting a message here flips that, so ANY failure within the set collapses into this one summary. This is meant for nuanced compound validations where the inner rule errors are an implementation detail the client does not care about, and "yeah thats not right" is a kinder thing to surface than whichever regex or length check happened to trip.

A real misconfiguration (an InternalError from a sub-rule, like "only a map can be validated") is still surfaced as-is and NOT masked, otherwise a genuine bug would hide behind the friendly message.

func (AllOfRule) ErrorObject added in v1.3.0

func (r AllOfRule) ErrorObject(err Error) AllOfRule

ErrorObject sets the whole error struct to surface when any sub-rule fails, the same way AllOfRule.Error sets just the message. Pass a fully built Error when you also need to control the translation code or params.

func (AllOfRule) Validate added in v1.2.0

func (r AllOfRule) Validate(value any) error

Validate implements Rule.

func (AllOfRule) ValidateWithContext added in v1.2.0

func (r AllOfRule) ValidateWithContext(ctx context.Context, value any) error

ValidateWithContext implements RuleWithContext. It threads ctx through to every sub-rule so a context-aware rule (or a nested OneOf) inside the set still sees it.

type BetweenRule added in v1.1.0

type BetweenRule[T Threshold] struct {
	// contains filtered or unexported fields
}

BetweenRule is a validation rule that checks if a value is within a range.

func Between added in v1.1.0

func Between[T Threshold](min, max T) BetweenRule[T]

Between returns a validation rule that checks if a value is within the inclusive range [min, max]. By calling Exclusive, both boundaries are excluded from the accepted range. Note that the value being checked and the boundary values must be of the same type. Only int, uint, float and time.Time types are supported. An empty value is considered valid. Please use the Required rule to make sure a value is not empty.

func (BetweenRule[T]) Error added in v1.1.0

func (r BetweenRule[T]) Error(message string) BetweenRule[T]

Error sets the error message for the rule.

func (BetweenRule[T]) ErrorObject added in v1.1.0

func (r BetweenRule[T]) ErrorObject(err Error) BetweenRule[T]

ErrorObject sets the error struct for the rule.

func (BetweenRule[T]) Exclusive added in v1.1.0

func (r BetweenRule[T]) Exclusive() BetweenRule[T]

Exclusive sets the comparison to exclude both boundary values.

func (BetweenRule[T]) Validate added in v1.1.0

func (r BetweenRule[T]) Validate(value any) error

Validate checks if the given value is within the range.

type DateRule

type DateRule struct {
	// contains filtered or unexported fields
}

DateRule is a validation rule that validates date/time string values.

func Date

func Date(layout string) DateRule

Date returns a validation rule that checks if a string value is in a format that can be parsed into a date. The format of the date should be specified as the layout parameter which accepts the same value as that for time.Parse. For example,

validation.Date(time.ANSIC)
validation.Date("02 Jan 06 15:04 MST")
validation.Date("2006-01-02")

By calling Min() and/or Max(), you can let the Date rule to check if a parsed date value is within the specified date range.

An empty value is considered valid. Use the Required rule to make sure a value is not empty.

func (DateRule) Error

func (r DateRule) Error(message string) DateRule

Error sets the error message that is used when the value being validated is not a valid date.

func (DateRule) ErrorObject

func (r DateRule) ErrorObject(err Error) DateRule

ErrorObject sets the error struct that is used when the value being validated is not a valid date..

func (DateRule) Max

func (r DateRule) Max(max time.Time) DateRule

Max sets the maximum date range. A zero value means skipping the maximum range validation.

func (DateRule) Min

func (r DateRule) Min(min time.Time) DateRule

Min sets the minimum date range. A zero value means skipping the minimum range validation.

func (DateRule) RangeError

func (r DateRule) RangeError(message string) DateRule

RangeError sets the error message that is used when the value being validated is out of the specified Min/Max date range.

func (DateRule) RangeErrorObject

func (r DateRule) RangeErrorObject(err Error) DateRule

RangeErrorObject sets the error struct that is used when the value being validated is out of the specified Min/Max date range.

func (DateRule) Validate

func (r DateRule) Validate(value any) error

Validate checks if the given value is a valid date.

type EachRule

type EachRule struct {
	// contains filtered or unexported fields
}

EachRule is a validation rule that validates elements in a map/slice/array using the specified list of rules.

func Each

func Each(rules ...Rule) EachRule

Each returns a validation rule that loops through an iterable (map, slice or array) and validates each value inside with the provided rules. An empty iterable is considered valid. Use the Required rule to make sure the iterable is not empty.

func (EachRule) Validate

func (r EachRule) Validate(value any) error

Validate loops through the given iterable and calls the Ozzo Validate() method for each value.

func (EachRule) ValidateWithContext

func (r EachRule) ValidateWithContext(ctx context.Context, value any) error

ValidateWithContext loops through the given iterable and calls the Ozzo ValidateWithContext() method for each value.

type EqFieldRule added in v1.1.0

type EqFieldRule[T any] struct {
	// contains filtered or unexported fields
}

EqFieldRule is a validation rule that checks if a value equals another field.

func EqField added in v1.1.0

func EqField[T any](other *T) EqFieldRule[T]

EqField returns a validation rule that checks if a value is equal to the value pointed to by other. It is intended for comparing two struct fields, for example a password and its confirmation. Pass a pointer to the sibling field, the same way it is passed to Field:

validation.ValidateStruct(&s,
    validation.Field(&s.Password, validation.Required),
    validation.Field(&s.ConfirmPassword, validation.EqField(&s.Password)),
)

reflect.DeepEqual() is used to determine if the two values are equal. An empty value is considered valid. Use the Required rule to make sure a value is not empty.

func (EqFieldRule[T]) Error added in v1.1.0

func (r EqFieldRule[T]) Error(message string) EqFieldRule[T]

Error sets the error message for the rule.

func (EqFieldRule[T]) ErrorObject added in v1.1.0

func (r EqFieldRule[T]) ErrorObject(err Error) EqFieldRule[T]

ErrorObject sets the error struct for the rule.

func (EqFieldRule[T]) Validate added in v1.1.0

func (r EqFieldRule[T]) Validate(value any) error

Validate checks if the given value is valid or not.

type EqRule added in v1.1.0

type EqRule[T any] struct {
	// contains filtered or unexported fields
}

EqRule is a validation rule that checks if a value is equal to the expected value.

func Eq added in v1.1.0

func Eq[T any](expected T) EqRule[T]

Eq returns a validation rule that checks if a value is equal to the given value. reflect.DeepEqual() is used to determine if two values are equal. An empty value is considered valid. Use the Required rule to make sure a value is not empty.

func (EqRule[T]) Error added in v1.1.0

func (r EqRule[T]) Error(message string) EqRule[T]

Error sets the error message for the rule.

func (EqRule[T]) ErrorObject added in v1.1.0

func (r EqRule[T]) ErrorObject(err Error) EqRule[T]

ErrorObject sets the error struct for the rule.

func (EqRule[T]) Validate added in v1.1.0

func (r EqRule[T]) Validate(value any) error

Validate checks if the given value is valid or not.

type ErrFieldNotFound

type ErrFieldNotFound int

ErrFieldNotFound is the error that a field cannot be found in the struct.

func (ErrFieldNotFound) Error

func (e ErrFieldNotFound) Error() string

Error returns the error string of ErrFieldNotFound.

type ErrFieldPointer

type ErrFieldPointer int

ErrFieldPointer is the error that a field is not specified as a pointer.

func (ErrFieldPointer) Error

func (e ErrFieldPointer) Error() string

Error returns the error string of ErrFieldPointer.

type Error

type Error interface {
	Error() string
	Code() string
	Message() string
	SetMessage(string) Error
	Params() map[string]any
	SetParams(map[string]any) Error
}

Error interface represents an validation error

func NewError

func NewError(code, message string) Error

NewError create new validation error.

type ErrorObject

type ErrorObject struct {
	// contains filtered or unexported fields
}

ErrorObject is the default validation error that implements the Error interface.

func (ErrorObject) AddParam

func (e ErrorObject) AddParam(name string, value any) Error

AddParam add parameter to the error's parameters.

func (ErrorObject) Code

func (e ErrorObject) Code() string

Code get the error's translation code.

func (ErrorObject) Error

func (e ErrorObject) Error() string

Error returns the error message.

func (ErrorObject) Message

func (e ErrorObject) Message() string

Message return the error's message.

func (ErrorObject) Params

func (e ErrorObject) Params() map[string]any

Params returns the error's params.

func (ErrorObject) SetCode

func (e ErrorObject) SetCode(code string) Error

SetCode set the error's translation code.

func (ErrorObject) SetMessage

func (e ErrorObject) SetMessage(message string) Error

SetMessage set the error's message.

func (ErrorObject) SetParams

func (e ErrorObject) SetParams(params map[string]any) Error

SetParams set the error's params.

type Errors

type Errors map[string]error

Errors represents the validation errors that are indexed by struct field names, map or slice keys. values are Error or Errors (for map, slice and array error value is Errors).

func (Errors) Error

func (es Errors) Error() string

Error returns the error string of Errors.

func (Errors) Filter

func (es Errors) Filter() error

Filter removes all nils from Errors and returns back the updated Errors as an error. If the length of Errors becomes 0, it will return nil.

func (Errors) MarshalJSON

func (es Errors) MarshalJSON() ([]byte, error)

MarshalJSON converts the Errors into a valid JSON.

type FieldRules

type FieldRules struct {
	// contains filtered or unexported fields
}

FieldRules represents a rule set associated with a struct field.

func Field

func Field[T any](fieldPtr *T, rules ...Rule) *FieldRules

Field specifies a struct field and the corresponding validation rules. The struct field must be specified as a pointer to it.

type Float added in v1.0.6

type Float interface {
	~float32 | ~float64
}

Float is a constraint that permits any floating-point type.

type InRule

type InRule[T any] struct {
	// contains filtered or unexported fields
}

InRule is a validation rule that validates if a value can be found in the given list of values.

func In

func In[T any](values ...T) InRule[T]

In returns a validation rule that checks if a value can be found in the given list of values. reflect.DeepEqual() will be used to determine if two values are equal. For more details please refer to https://golang.org/pkg/reflect/#DeepEqual An empty value is considered valid. Use the Required rule to make sure a value is not empty.

func (InRule[T]) Error

func (r InRule[T]) Error(message string) InRule[T]

Error sets the error message for the rule.

func (InRule[T]) ErrorObject

func (r InRule[T]) ErrorObject(err Error) InRule[T]

ErrorObject sets the error struct for the rule.

func (InRule[T]) Validate

func (r InRule[T]) Validate(value any) error

Validate checks if the given value is valid or not.

type Integer added in v1.0.6

type Integer interface {
	Signed | Unsigned
}

Integer is a constraint that permits any integer type.

type InternalError

type InternalError interface {
	error
	InternalError() error
}

InternalError represents an error that should NOT be treated as a validation error.

func NewInternalError

func NewInternalError(err error) InternalError

NewInternalError wraps a given error into an InternalError.

type KeyRules

type KeyRules[K comparable] struct {
	// contains filtered or unexported fields
}

KeyRules represents a rule set associated with a map key.

func Key

func Key[K comparable](key K, rules ...Rule) *KeyRules[K]

Key specifies a map key and the corresponding validation rules.

func (*KeyRules[K]) Optional deprecated

func (r *KeyRules[K]) Optional() *KeyRules[K]

Deprecated: Use Required instead.

Optional configures the rule to ignore the key if missing.

func (*KeyRules[K]) Required added in v1.0.4

func (r *KeyRules[K]) Required(required bool) *KeyRules[K]

Required sets whether or not this key is required. If it is optional then you can pass false to this function. Not calling this function will default to the key being required.

type LengthRule

type LengthRule struct {
	// contains filtered or unexported fields
}

LengthRule is a validation rule that checks if a value's length is within the specified range.

func Length

func Length(min, max int) LengthRule

Length returns a validation rule that checks if a value's length is within the specified range. If max is 0, it means there is no upper bound for the length. This rule should only be used for validating strings, slices, maps, and arrays. An empty value is considered valid. Use the Required rule to make sure a value is not empty.

func RuneLength

func RuneLength(min, max int) LengthRule

RuneLength returns a validation rule that checks if a string's rune length is within the specified range. If max is 0, it means there is no upper bound for the length. This rule should only be used for validating strings, slices, maps, and arrays. An empty value is considered valid. Use the Required rule to make sure a value is not empty. If the value being validated is not a string, the rule works the same as Length.

func (LengthRule) Error

func (r LengthRule) Error(message string) LengthRule

Error sets the error message for the rule.

func (LengthRule) ErrorObject

func (r LengthRule) ErrorObject(err Error) LengthRule

ErrorObject sets the error struct for the rule.

func (LengthRule) Validate

func (r LengthRule) Validate(value any) error

Validate checks if the given value is valid or not.

type MapRule

type MapRule[K comparable] struct {
	// contains filtered or unexported fields
}

MapRule represents a rule set associated with a map.

func Map

func Map[K comparable](keys ...*KeyRules[K]) MapRule[K]

Map returns a validation rule that checks the keys and values of a map. This rule should only be used for validating maps, or a validation error will be reported. Use Key() to specify map keys that need to be validated. Each Key() call specifies a single key which can be associated with multiple rules. For example,

validation.Map(
    validation.Key("Name", validation.Required),
    validation.Key("Value", validation.Required, validation.Length(5, 10)),
)

A nil value is considered valid. Use the Required rule to make sure a map value is present.

func (MapRule[K]) AllowExtraKeys

func (r MapRule[K]) AllowExtraKeys() MapRule[K]

AllowExtraKeys configures the rule to ignore extra keys.

func (MapRule[K]) Validate

func (r MapRule[K]) Validate(m any) error

Validate checks if the given value is valid or not.

func (MapRule[K]) ValidateWithContext

func (r MapRule[K]) ValidateWithContext(ctx context.Context, m any) error

ValidateWithContext checks if the given value is valid or not.

type MatchRule

type MatchRule struct {
	// contains filtered or unexported fields
}

MatchRule is a validation rule that checks if a value matches the specified regular expression.

func Match

func Match(re *regexp.Regexp) MatchRule

Match returns a validation rule that checks if a value matches the specified regular expression. This rule should only be used for validating strings and byte slices, or a validation error will be reported. An empty value is considered valid. Use the Required rule to make sure a value is not empty.

func (MatchRule) Error

func (r MatchRule) Error(message string) MatchRule

Error sets the error message for the rule.

func (MatchRule) ErrorObject

func (r MatchRule) ErrorObject(err Error) MatchRule

ErrorObject sets the error struct for the rule.

func (MatchRule) Validate

func (r MatchRule) Validate(value any) error

Validate checks if the given value is valid or not.

type MultipleOfRule

type MultipleOfRule[T Integer] struct {
	// contains filtered or unexported fields
}

MultipleOfRule is a validation rule that checks if a value is a multiple of the "base" value.

func MultipleOf

func MultipleOf[T Integer](base T) MultipleOfRule[T]

MultipleOf returns a validation rule that checks if a value is a multiple of the "base" value. Note that "base" should be of integer type.

func (MultipleOfRule[T]) Error

func (r MultipleOfRule[T]) Error(message string) MultipleOfRule[T]

Error sets the error message for the rule.

func (MultipleOfRule[T]) ErrorObject

func (r MultipleOfRule[T]) ErrorObject(err Error) MultipleOfRule[T]

ErrorObject sets the error struct for the rule.

func (MultipleOfRule[T]) Validate

func (r MultipleOfRule[T]) Validate(value any) error

Validate checks if the value is a multiple of the "base" value.

type NotEqFieldRule added in v1.1.0

type NotEqFieldRule[T any] struct {
	// contains filtered or unexported fields
}

NotEqFieldRule is a validation rule that checks if a value differs from another field.

func NotEqField added in v1.1.0

func NotEqField[T any](other *T) NotEqFieldRule[T]

NotEqField returns a validation rule that checks if a value differs from the value pointed to by other. It is intended for comparing two struct fields, for example a new password that must not match the current one. Pass a pointer to the sibling field, the same way it is passed to Field:

validation.ValidateStruct(&s,
    validation.Field(&s.NewPassword, validation.NotEqField(&s.OldPassword)),
)

reflect.DeepEqual() is used to determine if the two values are equal. An empty value is considered valid. Use the Required rule to make sure a value is not empty.

func (NotEqFieldRule[T]) Error added in v1.1.0

func (r NotEqFieldRule[T]) Error(message string) NotEqFieldRule[T]

Error sets the error message for the rule.

func (NotEqFieldRule[T]) ErrorObject added in v1.1.0

func (r NotEqFieldRule[T]) ErrorObject(err Error) NotEqFieldRule[T]

ErrorObject sets the error struct for the rule.

func (NotEqFieldRule[T]) Validate added in v1.1.0

func (r NotEqFieldRule[T]) Validate(value any) error

Validate checks if the given value is valid or not.

type NotEqRule added in v1.1.0

type NotEqRule[T any] struct {
	// contains filtered or unexported fields
}

NotEqRule is a validation rule that checks if a value is not equal to the forbidden value.

func NotEq added in v1.1.0

func NotEq[T any](forbidden T) NotEqRule[T]

NotEq returns a validation rule that checks if a value is not equal to the given value. reflect.DeepEqual() is used to determine if two values are equal. An empty value is considered valid. Use the Required rule to make sure a value is not empty.

func (NotEqRule[T]) Error added in v1.1.0

func (r NotEqRule[T]) Error(message string) NotEqRule[T]

Error sets the error message for the rule.

func (NotEqRule[T]) ErrorObject added in v1.1.0

func (r NotEqRule[T]) ErrorObject(err Error) NotEqRule[T]

ErrorObject sets the error struct for the rule.

func (NotEqRule[T]) Validate added in v1.1.0

func (r NotEqRule[T]) Validate(value any) error

Validate checks if the given value is valid or not.

type NotInRule

type NotInRule[T any] struct {
	// contains filtered or unexported fields
}

NotInRule is a validation rule that checks if a value is absent from the given list of values.

func NotIn

func NotIn[T any](values ...T) NotInRule[T]

NotIn returns a validation rule that checks if a value is absent from the given list of values. Note that the value being checked and the possible range of values must be of the same type. An empty value is considered valid. Use the Required rule to make sure a value is not empty.

func (NotInRule[T]) Error

func (r NotInRule[T]) Error(message string) NotInRule[T]

Error sets the error message for the rule.

func (NotInRule[T]) ErrorObject

func (r NotInRule[T]) ErrorObject(err Error) NotInRule[T]

ErrorObject sets the error struct for the rule.

func (NotInRule[T]) Validate

func (r NotInRule[T]) Validate(value any) error

Validate checks if the given value is valid or not.

type OneOfError added in v1.1.0

type OneOfError []error

OneOfError is the error returned when a value matches none of the alternative schemas of a union (MatchOneOf, OneOf or MatchOneOfStruct). Entries are in schema order; each is normally the Errors produced by one schema attempt, though an entry may be any error (for example a nested OneOfError, or a scalar rule's error when a schema is a single rule rather than a map/struct shape).

It marshals to JSON as

{"oneOf": [<entry>, <entry>, ...]}

so a client can see each shape the input could have matched. A union with a single alternative still marshals as a one-element oneOf array — the shape is uniform regardless of how many alternatives there are.

OneOfError is returned unwrapped (it is not boxed in another error type), so when it sits as a value inside a parent Errors, Errors.MarshalJSON serializes it structurally instead of collapsing it to a string.

func (OneOfError) Error added in v1.1.0

func (e OneOfError) Error() string

Error implements [error].

func (OneOfError) MarshalJSON added in v1.1.0

func (e OneOfError) MarshalJSON() ([]byte, error)

MarshalJSON serializes the union failure as {"oneOf": [...]}. Each entry is emitted via its own json.Marshaler when it implements one — so an Errors entry becomes a {field: message} object and a nested OneOfError keeps its {"oneOf": ...} shape — otherwise it falls back to the entry's message string.

func (OneOfError) Unwrap added in v1.1.0

func (e OneOfError) Unwrap() []error

Unwrap exposes the per-schema errors to errors.Is and errors.As.

type OneOfRule added in v1.1.0

type OneOfRule struct {
	// contains filtered or unexported fields
}

OneOfRule is the rule produced by OneOf.

func OneOf added in v1.1.0

func OneOf(schemas ...Rule) OneOfRule

OneOf returns a validation Rule that passes when the value matches at least one of the given schemas. It is the rule form of MatchOneOf for when you only need pass/fail (and want to compose or nest a union inside another rule chain). Use MatchOneOf when you need to know which schema matched in order to act on the input. On failure the rule's error is a OneOfError.

By default OneOf uses anyOf semantics: the first matching schema wins and evaluation short-circuits. Call OneOfRule.Strict to require that exactly one schema match.

func (OneOfRule) Strict added in v1.1.0

func (r OneOfRule) Strict() OneOfRule

Strict returns a copy of the rule that requires exactly one schema to match. If more than one matches it fails with ErrAmbiguousMatch, which flags schemas that are not mutually exclusive. Unlike the default anyOf behavior, strict mode always evaluates every schema.

func (OneOfRule) Validate added in v1.1.0

func (r OneOfRule) Validate(value any) error

Validate implements Rule.

func (OneOfRule) ValidateWithContext added in v1.1.0

func (r OneOfRule) ValidateWithContext(ctx context.Context, value any) error

ValidateWithContext implements RuleWithContext.

type RequiredRule

type RequiredRule struct {
	// contains filtered or unexported fields
}

RequiredRule is a rule that checks if a value is not empty.

func (RequiredRule) Error

func (r RequiredRule) Error(message string) RequiredRule

Error sets the error message for the rule.

func (RequiredRule) ErrorObject

func (r RequiredRule) ErrorObject(err Error) RequiredRule

ErrorObject sets the error struct for the rule.

func (RequiredRule) Validate

func (r RequiredRule) Validate(value any) error

Validate checks if the given value is valid or not.

func (RequiredRule) When

func (r RequiredRule) When(condition bool) RequiredRule

When sets the condition that determines if the validation should be performed.

type Rule

type Rule interface {
	// Validate validates a value and returns a value if validation fails.
	Validate(value any) error
}

Rule represents a validation rule.

func By

func By(f RuleFunc) Rule

By wraps a RuleFunc into a Rule.

func WithContext

func WithContext(f RuleWithContextFunc) Rule

WithContext wraps a RuleWithContextFunc into a context-aware Rule.

type RuleFunc

type RuleFunc func(value any) error

RuleFunc represents a validator function. You may wrap it as a Rule by calling By().

type RuleWithContext

type RuleWithContext interface {
	// ValidateWithContext validates a value and returns a value if validation fails.
	ValidateWithContext(ctx context.Context, value any) error
}

RuleWithContext represents a context-aware validation rule.

type RuleWithContextFunc

type RuleWithContextFunc func(ctx context.Context, value any) error

RuleWithContextFunc represents a validator function that is context-aware. You may wrap it as a Rule by calling WithContext().

type Signed added in v1.0.6

type Signed interface {
	~int | ~int8 | ~int16 | ~int32 | ~int64
}

Signed is a constraint that permits any signed integer type.

type StringRule

type StringRule struct {
	// contains filtered or unexported fields
}

StringRule is a rule that checks a string variable using a specified stringValidator.

func Contains added in v1.1.0

func Contains(substring string) StringRule

Contains returns a validation rule that checks if a string contains the given substring. An empty value is considered valid. Use the Required rule to make sure a value is not empty.

func HasPrefix added in v1.1.0

func HasPrefix(prefix string) StringRule

HasPrefix returns a validation rule that checks if a string starts with the given prefix. An empty value is considered valid. Use the Required rule to make sure a value is not empty.

func HasSuffix added in v1.1.0

func HasSuffix(suffix string) StringRule

HasSuffix returns a validation rule that checks if a string ends with the given suffix. An empty value is considered valid. Use the Required rule to make sure a value is not empty.

func NewStringRule

func NewStringRule(validator stringValidator, message string) StringRule

NewStringRule creates a new validation rule using a function that takes a string value and returns a bool. The rule returned will use the function to check if a given string or byte slice is valid or not. An empty value is considered to be valid. Please use the Required rule to make sure a value is not empty.

func NewStringRuleWithError

func NewStringRuleWithError(validator stringValidator, err Error) StringRule

NewStringRuleWithError creates a new validation rule using a function that takes a string value and returns a bool. The rule returned will use the function to check if a given string or byte slice is valid or not. An empty value is considered to be valid. Please use the Required rule to make sure a value is not empty.

func (StringRule) Error

func (r StringRule) Error(message string) StringRule

Error sets the error message for the rule.

func (StringRule) ErrorObject

func (r StringRule) ErrorObject(err Error) StringRule

ErrorObject sets the error struct for the rule.

func (StringRule) Validate

func (r StringRule) Validate(value any) error

Validate checks if the given value is valid or not.

type Threshold added in v1.0.6

type Threshold interface {
	Integer | Float | time.Time
}

Threshold is a constraint that permits the value types supported by the Min and Max rules: any integer type, any floating-point type, or time.Time.

type ThresholdRule

type ThresholdRule[T Threshold] struct {
	// contains filtered or unexported fields
}

ThresholdRule is a validation rule that checks if a value satisfies the specified threshold requirement.

func Gt added in v1.1.0

func Gt[T Threshold](min T) ThresholdRule[T]

Gt returns a validation rule that checks if a value is strictly greater than the specified value. This is equivalent to Min(min).Exclusive() and is provided as a more readable alternative. Note that the value being checked and the threshold value must be of the same type. Only int, uint, float and time.Time types are supported. An empty value is considered valid. Please use the Required rule to make sure a value is not empty.

func Gte added in v1.1.0

func Gte[T Threshold](min T) ThresholdRule[T]

Gte returns a validation rule that checks if a value is greater than or equal to the specified value. This is equivalent to Min(min). Note that the value being checked and the threshold value must be of the same type. Only int, uint, float and time.Time types are supported. An empty value is considered valid. Please use the Required rule to make sure a value is not empty.

func Lt added in v1.1.0

func Lt[T Threshold](max T) ThresholdRule[T]

Lt returns a validation rule that checks if a value is strictly less than the specified value. This is equivalent to Max(max).Exclusive() and is provided as a more readable alternative. Note that the value being checked and the threshold value must be of the same type. Only int, uint, float and time.Time types are supported. An empty value is considered valid. Please use the Required rule to make sure a value is not empty.

func Lte added in v1.1.0

func Lte[T Threshold](max T) ThresholdRule[T]

Lte returns a validation rule that checks if a value is less than or equal to the specified value. This is equivalent to Max(max). Note that the value being checked and the threshold value must be of the same type. Only int, uint, float and time.Time types are supported. An empty value is considered valid. Please use the Required rule to make sure a value is not empty.

func Max

func Max[T Threshold](max T) ThresholdRule[T]

Max returns a validation rule that checks if a value is less or equal than the specified value. By calling Exclusive, the rule will check if the value is strictly less than the specified value. Note that the value being checked and the threshold value must be of the same type. Only int, uint, float and time.Time types are supported. An empty value is considered valid. Please use the Required rule to make sure a value is not empty.

func Min

func Min[T Threshold](min T) ThresholdRule[T]

Min returns a validation rule that checks if a value is greater or equal than the specified value. By calling Exclusive, the rule will check if the value is strictly greater than the specified value. Note that the value being checked and the threshold value must be of the same type. Only int, uint, float and time.Time types are supported. An empty value is considered valid. Please use the Required rule to make sure a value is not empty.

func (ThresholdRule[T]) Error

func (r ThresholdRule[T]) Error(message string) ThresholdRule[T]

Error sets the error message for the rule.

func (ThresholdRule[T]) ErrorObject

func (r ThresholdRule[T]) ErrorObject(err Error) ThresholdRule[T]

ErrorObject sets the error struct for the rule.

func (ThresholdRule[T]) Exclusive

func (r ThresholdRule[T]) Exclusive() ThresholdRule[T]

Exclusive sets the comparison to exclude the boundary value.

func (ThresholdRule[T]) Validate

func (r ThresholdRule[T]) Validate(value any) error

Validate checks if the given value is valid or not.

type TypeRule added in v1.2.0

type TypeRule struct {
	// contains filtered or unexported fields
}

TypeRule is a validation rule that asserts the underlying type of a value. Use the package-level IsString, IsInteger, IsFloat, and IsBoolean rules rather than constructing one directly.

func (TypeRule) Error added in v1.2.0

func (r TypeRule) Error(message string) TypeRule

Error sets the error message for the rule.

func (TypeRule) ErrorObject added in v1.2.0

func (r TypeRule) ErrorObject(err Error) TypeRule

ErrorObject sets the error struct for the rule.

func (TypeRule) Validate added in v1.2.0

func (r TypeRule) Validate(value any) error

Validate checks that the value's underlying type matches the asserted type.

type Unsigned added in v1.0.6

type Unsigned interface {
	~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
}

Unsigned is a constraint that permits any unsigned integer type.

type Validatable

type Validatable interface {
	// Validate validates the data and returns an error if validation fails.
	Validate() error
}

Validatable is the interface indicating the type implementing it supports data validation.

type ValidatableWithContext

type ValidatableWithContext interface {
	// ValidateWithContext validates the data with the given context and returns an error if validation fails.
	ValidateWithContext(ctx context.Context) error
}

ValidatableWithContext is the interface indicating the type implementing it supports context-aware data validation.

type WhenRule

type WhenRule struct {
	// contains filtered or unexported fields
}

WhenRule is a validation rule that executes the given list of rules when the condition is true.

func When

func When(condition bool, rules ...Rule) WhenRule

When returns a validation rule that executes the given list of rules when the condition is true.

func (WhenRule) Else

func (r WhenRule) Else(rules ...Rule) WhenRule

Else returns a validation rule that executes the given list of rules when the condition is false.

func (WhenRule) Validate

func (r WhenRule) Validate(value any) error

Validate checks if the condition is true and if so, it validates the value using the specified rules.

func (WhenRule) ValidateWithContext

func (r WhenRule) ValidateWithContext(ctx context.Context, value any) error

ValidateWithContext checks if the condition is true and if so, it validates the value using the specified rules.

Directories

Path Synopsis
Package govalidator is package of validators and sanitizers for strings, structs and collections.
Package govalidator is package of validators and sanitizers for strings, structs and collections.
Package is provides a list of commonly used string validation rules.
Package is provides a list of commonly used string validation rules.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL