chore: move go-ozzo/ozzo-validation to invopop/validation
invpop/validation is a fork of go-ozzo/ozzo-validation with some additional bug fixes. Specifically we need: https://github.com/invopop/validation/pull/1
This commit is contained in:
committed by
Ralf Haferkamp
parent
1b47707e2f
commit
90f7cc23f4
Generated
Vendored
Generated
Vendored
Generated
Vendored
+143
-149
@@ -1,49 +1,54 @@
|
||||
# ozzo-validation
|
||||
# Go Validation
|
||||
|
||||
[](http://godoc.org/github.com/go-ozzo/ozzo-validation)
|
||||
[](https://travis-ci.org/go-ozzo/ozzo-validation)
|
||||
[](https://coveralls.io/github/go-ozzo/ozzo-validation?branch=master)
|
||||
[](https://goreportcard.com/report/github.com/go-ozzo/ozzo-validation)
|
||||
[](https://github.com/invopop/validation/actions/workflows/lint.yaml)
|
||||
[](https://github.com/invopop/validation/actions/workflows/test.yaml)
|
||||
[](http://godoc.org/github.com/invopop/validation)
|
||||
[](https://coveralls.io/github/invopop/validation?branch=main)
|
||||
[](https://goreportcard.com/report/github.com/invopop/validation)
|
||||

|
||||
|
||||
NOTE: This is a fork of the well known [ozzo-validation](https://github.com/go-ozzo/ozzo-validation) package which as of Feb 2023 doesn't appear to be under active maintenance for more than 2 years. At [Invopop](https://invopop.com) we use this library extensively, so it only felt appropriate to be more pro-active. We'll do out best to respond to issues and review or merge any pull requests.
|
||||
|
||||
## Description
|
||||
|
||||
ozzo-validation is a Go package that provides configurable and extensible data validation capabilities.
|
||||
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.
|
||||
- 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.
|
||||
|
||||
For an example on how this library is used in an application, please refer to [go-rest-api](https://github.com/qiangxue/go-rest-api) which is a starter kit for building RESTful APIs in Go.
|
||||
|
||||
For further examples, checkout the [GOBL project](https://github.com/invopop/gobl) which uses validation extensively.
|
||||
|
||||
## Requirements
|
||||
|
||||
Go 1.13 or above.
|
||||
|
||||
Go 1.16 or above.
|
||||
|
||||
## Getting Started
|
||||
|
||||
The ozzo-validation package mainly includes a set of validation rules and two validation methods. You use
|
||||
The validation package mainly includes a set of validation rules and two validation methods. You use
|
||||
validation rules to describe how a value should be considered valid, and you call either `validation.Validate()`
|
||||
or `validation.ValidateStruct()` to validate the value.
|
||||
|
||||
|
||||
### Installation
|
||||
|
||||
Run the following command to install the package:
|
||||
|
||||
```
|
||||
go get github.com/go-ozzo/ozzo-validation
|
||||
go get github.com/invopop/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,
|
||||
For a simple value, such as a string or an integer, you may use `validation.Validate()` to validate it. For example,
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -51,8 +56,8 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-ozzo/ozzo-validation/v4"
|
||||
"github.com/go-ozzo/ozzo-validation/v4/is"
|
||||
"github.com/invopop/validation"
|
||||
"github.com/invopop/validation/is"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -72,13 +77,12 @@ The method `validation.Validate()` will run through the rules in the order that
|
||||
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
|
||||
to achieve this purpose. A single struct can have rules for multiple fields, and a field can be associated with multiple
|
||||
rules. For example,
|
||||
|
||||
```go
|
||||
@@ -91,10 +95,10 @@ type Address struct {
|
||||
|
||||
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)),
|
||||
// Street cannot be empty, and the length must between 2 and 50
|
||||
validation.Field(&a.Street, validation.Required, validation.Length(2, 50)),
|
||||
// City cannot be empty, and the length must between 2 and 50
|
||||
validation.Field(&a.City, validation.Required, validation.Length(2, 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
|
||||
@@ -115,19 +119,18 @@ fmt.Println(err)
|
||||
// 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
|
||||
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.
|
||||
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`.
|
||||
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
|
||||
in this situation. A single map can have rules for multiple keys, and a key can be associated with multiple
|
||||
rules. For example,
|
||||
|
||||
```go
|
||||
@@ -150,10 +153,10 @@ err := validation.Validate(c,
|
||||
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)),
|
||||
// Street cannot be empty, and the length must between 2 and 50
|
||||
validation.Key("Street", validation.Required, validation.Length(2, 50)),
|
||||
// City cannot be empty, and the length must between 2 and 50
|
||||
validation.Key("City", validation.Required, validation.Length(2, 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
|
||||
@@ -166,18 +169,17 @@ fmt.Println(err)
|
||||
// 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`.
|
||||
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.
|
||||
|
||||
|
||||
### Validation Errors
|
||||
|
||||
The `validation.ValidateStruct` method returns validation errors found in struct fields in terms of `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
|
||||
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,
|
||||
|
||||
```go
|
||||
@@ -221,16 +223,15 @@ fmt.Println(err)
|
||||
// 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
|
||||
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
|
||||
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.
|
||||
@@ -252,23 +253,22 @@ if err := a.Validate(); err != nil {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Validatable Types
|
||||
|
||||
A type is validatable if it implements the `validation.Validatable` interface.
|
||||
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.
|
||||
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
|
||||
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
|
||||
> 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
|
||||
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.
|
||||
|
||||
@@ -332,8 +332,8 @@ fmt.Println(err)
|
||||
// 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.
|
||||
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
|
||||
|
||||
@@ -376,14 +376,12 @@ 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.
|
||||
@@ -395,7 +393,6 @@ In the second scenario, an input value is considered missing only if it is not e
|
||||
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).
|
||||
|
||||
|
||||
### Embedded Structs
|
||||
|
||||
The `validation.ValidateStruct` method will properly validate a struct that contains embedded structs. In particular,
|
||||
@@ -444,10 +441,9 @@ fmt.Println(err)
|
||||
// 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
|
||||
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:
|
||||
@@ -455,8 +451,8 @@ The following code implements the aforementioned examples:
|
||||
```go
|
||||
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.')),
|
||||
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.")),
|
||||
)
|
||||
```
|
||||
|
||||
@@ -467,8 +463,8 @@ The above code can also be simplified using the shortcut `validation.Required.Wh
|
||||
```go
|
||||
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.')),
|
||||
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.")),
|
||||
)
|
||||
```
|
||||
|
||||
@@ -488,16 +484,17 @@ fmt.Println(err)
|
||||
// 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*
|
||||
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:
|
||||
|
||||
```go
|
||||
validation.ErrRequired = validation.ErrRequired.SetMessage("the value is required")
|
||||
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
|
||||
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.
|
||||
|
||||
@@ -549,10 +546,9 @@ 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
|
||||
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.
|
||||
|
||||
```go
|
||||
@@ -577,21 +573,19 @@ func (u User) Validate() error {
|
||||
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
|
||||
|
||||
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()`.
|
||||
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 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,
|
||||
|
||||
|
||||
```go
|
||||
rule := validation.WithContext(func(ctx context.Context, value interface{}) error {
|
||||
if ctx.Value("secret") == value.(string) {
|
||||
@@ -609,94 +603,94 @@ fmt.Println(err)
|
||||
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:
|
||||
|
||||
* `In(...interface{})`: checks if a value can be found in the given list of values.
|
||||
* `NotIn(...interface{})`: checks if a value is NOT among the given list of values.
|
||||
* `Length(min, max int)`: checks if the length of a value is within the specified range.
|
||||
- `In(...interface{})`: checks if a value can be found in the given list of values.
|
||||
- `NotIn(...interface{})`: checks if a value is NOT among the given list of values.
|
||||
- `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.
|
||||
- `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.
|
||||
* `Min(min interface{})` and `Max(max interface{})`: checks if a value is within the specified range.
|
||||
- `Min(min interface{})` and `Max(max interface{})`: checks if a value is within the specified range.
|
||||
These two rules should only be used for validating int, uint, float and time.Time types.
|
||||
* `Match(*regexp.Regexp)`: checks if a value matches the specified regular expression.
|
||||
- `Match(*regexp.Regexp)`: checks if a value matches the specified regular expression.
|
||||
This rule should only be used for strings and byte slices.
|
||||
* `Date(layout string)`: checks if a string value is a date whose format is specified by the layout.
|
||||
- `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.
|
||||
* `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.
|
||||
* `Skip`: this is a special rule used to indicate that all rules following it should be skipped (including the nested ones).
|
||||
* `MultipleOf`: checks if the value is a multiple of the specified range.
|
||||
* `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.
|
||||
- `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.
|
||||
- `Skip`: this is a special rule used to indicate that all rules following it should be skipped (including the nested ones).
|
||||
- `MultipleOf`: checks if the value is a multiple of the specified range.
|
||||
- `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.
|
||||
|
||||
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.
|
||||
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
|
||||
* `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
|
||||
* `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
|
||||
- `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
|
||||
- `ULID`: validates if a string is a valid ULID
|
||||
- `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
|
||||
- `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
|
||||
- `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
|
||||
|
||||
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
+2
-4
@@ -27,7 +27,7 @@ type EachRule struct {
|
||||
|
||||
// Validate loops through the given iterable and calls the Ozzo Validate() method for each value.
|
||||
func (r EachRule) Validate(value interface{}) error {
|
||||
return r.ValidateWithContext(nil, value)
|
||||
return r.ValidateWithContext(context.Background(), value)
|
||||
}
|
||||
|
||||
// ValidateWithContext loops through the given iterable and calls the Ozzo ValidateWithContext() method for each value.
|
||||
@@ -78,10 +78,8 @@ func (r EachRule) getInterface(value reflect.Value) interface{} {
|
||||
if value.IsNil() {
|
||||
return nil
|
||||
}
|
||||
return value.Elem().Interface()
|
||||
default:
|
||||
return value.Interface()
|
||||
}
|
||||
return value.Interface()
|
||||
}
|
||||
|
||||
func (r EachRule) getString(value reflect.Value) string {
|
||||
Generated
Vendored
Generated
Vendored
Generated
Vendored
+6
-4
@@ -10,7 +10,7 @@ import (
|
||||
"unicode"
|
||||
|
||||
"github.com/asaskevich/govalidator"
|
||||
validation "github.com/go-ozzo/ozzo-validation/v4"
|
||||
"github.com/invopop/validation"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -58,6 +58,8 @@ var (
|
||||
ErrUUIDv5 = validation.NewError("validation_is_uuid_v5", "must be a valid UUID v5")
|
||||
// ErrUUID is the error that returns in case of an invalid UUID value.
|
||||
ErrUUID = validation.NewError("validation_is_uuid", "must be a valid UUID")
|
||||
// ErrULID is the error that returns in case of an invalid ULID value.
|
||||
ErrULID = validation.NewError("validation_is_ulid", "must be a valid ULID")
|
||||
// ErrCreditCard is the error that returns in case of an invalid credit card number.
|
||||
ErrCreditCard = validation.NewError("validation_is_credit_card", "must be a valid credit card number")
|
||||
// ErrISBN10 is the error that returns in case of an invalid ISBN-10 value.
|
||||
@@ -84,7 +86,7 @@ var (
|
||||
ErrBase64 = validation.NewError("validation_is_base64", "must be encoded in Base64")
|
||||
// ErrDataURI is the error that returns in case of an invalid data URI.
|
||||
ErrDataURI = validation.NewError("validation_is_data_uri", "must be a Base64-encoded data URI")
|
||||
// ErrE164 is the error that returns in case of an invalid e165.
|
||||
// ErrE164 is the error that returns in case of an invalid e164.
|
||||
ErrE164 = validation.NewError("validation_is_e164_number", "must be a valid E164 number")
|
||||
// ErrCountryCode2 is the error that returns in case of an invalid two-letter country code.
|
||||
ErrCountryCode2 = validation.NewError("validation_is_country_code_2_letter", "must be a valid two-letter country code")
|
||||
@@ -197,7 +199,7 @@ var (
|
||||
Base64 = validation.NewStringRuleWithError(govalidator.IsBase64, ErrBase64)
|
||||
// DataURI validates if a string is a valid base64-encoded data URI
|
||||
DataURI = validation.NewStringRuleWithError(govalidator.IsDataURI, ErrDataURI)
|
||||
// E164 validates if a string is a valid ISO3166 Alpha 2 country code
|
||||
// E164 validates if a string is a valid E164 telephone number
|
||||
E164 = validation.NewStringRuleWithError(isE164Number, ErrE164)
|
||||
// CountryCode2 validates if a string is a valid ISO3166 Alpha 2 country code
|
||||
CountryCode2 = validation.NewStringRuleWithError(govalidator.IsISO3166Alpha2, ErrCountryCode2)
|
||||
@@ -275,7 +277,7 @@ func isDomain(value string) bool {
|
||||
|
||||
func isUTFNumeric(value string) bool {
|
||||
for _, c := range value {
|
||||
if unicode.IsNumber(c) == false {
|
||||
if !unicode.IsNumber(c) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
Generated
Vendored
Generated
Vendored
+6
-5
@@ -41,10 +41,11 @@ type (
|
||||
// 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)),
|
||||
// )
|
||||
//
|
||||
// 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 Map(keys ...*KeyRules) MapRule {
|
||||
@@ -59,7 +60,7 @@ func (r MapRule) AllowExtraKeys() MapRule {
|
||||
|
||||
// Validate checks if the given value is valid or not.
|
||||
func (r MapRule) Validate(m interface{}) error {
|
||||
return r.ValidateWithContext(nil, m)
|
||||
return r.ValidateWithContext(context.Background(), m)
|
||||
}
|
||||
|
||||
// ValidateWithContext checks if the given value is valid or not.
|
||||
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
Generated
Vendored
+11
-11
@@ -47,20 +47,20 @@ func (e ErrFieldNotFound) Error() string {
|
||||
// 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.
|
||||
// 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 ValidateStruct(structPtr interface{}, fields ...*FieldRules) error {
|
||||
return ValidateStructWithContext(nil, structPtr, fields...)
|
||||
return ValidateStructWithContext(context.Background(), structPtr, fields...)
|
||||
}
|
||||
|
||||
// ValidateStructWithContext validates a struct with the given context.
|
||||
Generated
Vendored
Generated
Vendored
Generated
Vendored
+3
-5
@@ -20,7 +20,7 @@ type WhenRule struct {
|
||||
|
||||
// Validate checks if the condition is true and if so, it validates the value using the specified rules.
|
||||
func (r WhenRule) Validate(value interface{}) error {
|
||||
return r.ValidateWithContext(nil, value)
|
||||
return r.ValidateWithContext(context.Background(), value)
|
||||
}
|
||||
|
||||
// ValidateWithContext checks if the condition is true and if so, it validates the value using the specified rules.
|
||||
@@ -28,16 +28,14 @@ func (r WhenRule) ValidateWithContext(ctx context.Context, value interface{}) er
|
||||
if r.condition {
|
||||
if ctx == nil {
|
||||
return Validate(value, r.rules...)
|
||||
} else {
|
||||
return ValidateWithContext(ctx, value, r.rules...)
|
||||
}
|
||||
return ValidateWithContext(ctx, value, r.rules...)
|
||||
}
|
||||
|
||||
if ctx == nil {
|
||||
return Validate(value, r.elseRules...)
|
||||
} else {
|
||||
return ValidateWithContext(ctx, value, r.elseRules...)
|
||||
}
|
||||
return ValidateWithContext(ctx, value, r.elseRules...)
|
||||
}
|
||||
|
||||
// Else returns a validation rule that executes the given list of rules when the condition is false.
|
||||
Vendored
+4
-4
@@ -981,10 +981,6 @@ github.com/go-micro/plugins/v4/wrapper/monitoring/prometheus
|
||||
# github.com/go-micro/plugins/v4/wrapper/trace/opentelemetry v1.2.0
|
||||
## explicit; go 1.17
|
||||
github.com/go-micro/plugins/v4/wrapper/trace/opentelemetry
|
||||
# github.com/go-ozzo/ozzo-validation/v4 v4.3.0
|
||||
## explicit; go 1.13
|
||||
github.com/go-ozzo/ozzo-validation/v4
|
||||
github.com/go-ozzo/ozzo-validation/v4/is
|
||||
# github.com/go-playground/locales v0.14.1
|
||||
## explicit; go 1.17
|
||||
github.com/go-playground/locales
|
||||
@@ -1224,6 +1220,10 @@ github.com/imdario/mergo
|
||||
# github.com/inconshreveable/mousetrap v1.1.0
|
||||
## explicit; go 1.18
|
||||
github.com/inconshreveable/mousetrap
|
||||
# github.com/invopop/validation v0.3.0
|
||||
## explicit; go 1.16
|
||||
github.com/invopop/validation
|
||||
github.com/invopop/validation/is
|
||||
# github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99
|
||||
## explicit
|
||||
github.com/jbenet/go-context/io
|
||||
|
||||
Reference in New Issue
Block a user