Awesome Go

validate

CategoryValidation
SubcategoryValidation
Stars1,166

Go package for data validation and filtering. support validate Map, Struct, Request(Form, JSON, url.Values, Uploaded Files) data and more features

About validate

This large README is shown as a plain-text preview. Read the full README at the source

# Validate

[![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/gookit/validate)](https://github.com/gookit/validate)
[![GoDoc](https://pkg.go.dev/badge/github.com/gookit/validate.svg)](https://pkg.go.dev/github.com/gookit/validate)
![GitHub go.mod Go version](https://img.shields.io/github/go-mod/go-version/gookit/validate?style=flat-square)
[![Coverage Status](https://coveralls.io/repos/github/gookit/validate/badge.svg?branch=master)](https://coveralls.io/github/gookit/validate?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/gookit/validate)](https://goreportcard.com/report/github.com/gookit/validate)
[![Actions Status](https://github.com/gookit/validate/workflows/Unit-Tests/badge.svg)](https://github.com/gookit/validate/actions)

`validate` is a generic Go data validate and filter tool library.

> **[中文说明](README.zh-CN.md)**

- Support quick validate `Map`, `Struct`, `Request`(`Form`, `JSON`, `url.Values`, `UploadedFile`) data
  - Validating `http.Request` automatically collects data based on the request `Content-Type` value
  - Supports checking each child value in a slice. eg: `v.StringRule("tags.*", "required|string")`
- Support filter/sanitize/convert data before validate
- Support add custom filter/validator func
- Support scene settings, verify different fields in different scenes
- Support custom error messages, field translates.
  - Can use `message`, `label` tags in struct
- Customizable i18n aware error messages, built in `en`, `zh-CN`, `zh-TW`
- Built-in common data type filter/converter. see [Built In Filters](#built-in-filters)
- Many commonly used validators have been built in(**> 70**), see [Built In Validators](#built-in-validators)
- Can use `validate` in any frameworks, such as Gin, Echo, Chi and more
- Supports direct use of rules to validate value. eg: `validate.Val("[email protected]", "required|email")`

## Go Doc

- [Godoc for github](https://pkg.go.dev/github.com/gookit/validate/v2)

> **v2.0**: the module path is now `github.com/gookit/validate/v2` (requires Go 1.21+).
> See the [upgrade guide](docs/UPGRADE-v2.md) for migrating from v1.x.
>
> **Performance**: see [Benchmark comparison](docs/benchmark-v1-to-v2.md) for the v1.5.7 → v1.6.0 → v2.0.0 benchmark results.

Install:

```bash
go get github.com/gookit/validate/v2
```

## Validate Struct

Use the `validate` tag of the structure, you can quickly config a structure.

### Config the struct use tags

Field translations and error messages for structs can be quickly configured using the `message` and `label` tags.

- Support configuration field mapping through structure tag, read the value of `json` tag by default
- Support configuration error message via structure's `message` tag
- Support configuration field translation via structure's `label` tag

```go
package main

import (
	"fmt"
	"time"

	"github.com/gookit/validate/v2"
)

// UserForm struct
type UserForm struct {
	Name     string    `validate:"required|min_len:7" message:"required:{field} is required" label:"User Name"`
	Email    string    `validate:"email" message:"email is invalid" label:"User Email"`
	Age      int       `validate:"required|int|min:1|max:99" message:"int:age must int|min:age min value is 1"`
	CreateAt int       `validate:"min:1"`
	Safe     int       `validate:"-"`
	UpdateAt time.Time `validate:"required" message:"update time is required"`
	Code     string    `validate:"customValidator"`
	// ExtInfo nested struct
	ExtInfo struct{
		Homepage string `validate:"required" label:"Home Page"`
		CityName string
	} `validate:"required" label:"Home Page"`
}

// CustomValidator custom validator in the source struct.
func (f UserForm) CustomValidator(val string) bool {
	return len(val) == 4
}
```

### Config validate use struct methods

`validate` provides extended functionality:

The struct can implement three interfaces methods, which is convenient to do some customization:

- `ConfigValidation(v *Validation)` will be called after the validator instance is created
- `Messages() map[string]string` can customize the validator error message
- `Translates() map[string]string` can customize field translation

```go
package main

import (
	"fmt"
	"time"

	"github.com/gookit/validate/v2"
)

// UserForm struct
type UserForm struct {
	Name     string    `validate:"required|min_len:7"`
	Email    string    `validate:"email"`
	Age      int       `validate:"required|int|min:1|max:99"`
	CreateAt int       `validate:"min:1"`
	Safe     int       `validate:"-"`
	UpdateAt time.Time `validate:"required"`
	Code     string    `validate:"customValidator"`
	// ExtInfo nested struct
	ExtInfo struct{
		Homepage string `validate:"required"`
		CityName string
	} `validate:"required"`
}

// CustomValidator custom validator in the source struct.
func (f UserForm) CustomValidator(val string) bool {
	return len(val) == 4
}

// ConfigValidation config the Validation
// eg:
// - define validate scenes
func (f UserForm) ConfigValidation(v *validate.Validation) {
	v.WithScenes(validate.SValues{
		"add":    []string{"ExtInfo.Homepage", "Name", "Code"},
		"update": []string{"ExtInfo.CityName", "Name"},
	})
}

// Messages you can custom validator error messages. 
func (f UserForm) Messages() map[string]string {
	return validate.MS{
		"required": "oh! the {field} is required",
		"email": "email is invalid",
		"Name.required": "message for special field",
		"Age.int": "age must int",
		"Age.min": "age min value is 1",
	}
}

// Translates you can custom field translates. 
func (f UserForm) Translates() map[string]string {
	return validate.MS{
		"Name": "User Name",
		"Email": "User Email",
		"ExtInfo.Homepage": "Home Page",
	}
}
```

### Create and validating

Can use `validate.Struct(ptr)` quick create a validation instance. then call `v.Validate()` for validating.

```go
package main

import (
  "fmt"

  "github.com/gookit/validate/v2"
)

func main() {
	u := &UserForm{
		Name: "inhere",
	}
	
	v := validate.Struct(u)
	// v := validate.New(u)

	if v.Validate() { // validate ok
		// do something ...
	} else {
		fmt.Println(v.Errors) // all error messages
		fmt.Println(v.Errors.One()) // returns a random error message text
		fmt.Println(v.Errors.OneError()) // returns a random error
		fmt.Println(v.Errors.Field("Name")) // returns error messages of the field 
	}
}
```

### Sub-struct (nested) validation

By default (`CheckSubOnParentMarked=true`), a **named** sub-struct field
(`struct` / `*struct` / slice-of-struct / map-of-struct) is descended into to
collect its inner rules **only when it carries a `validate` tag**. The tag
**value may be empty** — `validate:""` is enough to mark the field. A named field
with **no** `validate` tag at all is **not** descended into. This is the Java
`@Valid` style of on-demand cascade, avoiding pointless recursion through the
whole struct tree.

**Anonymous embedded structs are exempt**: `type Bar struct { Foo }` (the field
is promoted and is part of the parent) **always cascades**, no tag needed. Only
**named** nested fields need the marker.

```go
type Address struct {
    City string `validate:"required"`
}
type User struct {
    Name string  `validate:"required"`
    Home Address `validate:"required"` // has tag -> descend, validates Home.City
    Work Address `validate:""`         // empty tag is also a marker -> descend
    Temp Address                       // no tag -> not descended, Temp.City ignored
}
```

To restore v1's unconditional cascade behaviour globally:

```go
validate.Config(func(o *validate.GlobalOption) {
	o.CheckSubOnParentMarked = false
})
```

> See the [upgrade guide](docs/UPGRADE-v2.md) for more on this behaviour change.

## Validate Map

You can also validate a MAP data directly.

```go
package main

import (
"fmt"

"github.com/gookit/validate/v2"
)

func main()  {
	m := map[string]any{
		"name":  "inhere",
		"age":   100,
		"oldSt": 1,
		"newSt": 2,
		"email": "[email protected]",
		"tags": []string{"go", "php", "java"},
	}

	v := validate.Map(m)
	// v := validate.New(m)
	v.AddRule("name", "required")
	v.AddRule("name", "minLen", 7)
	v.AddRule("age", "max", 99)
	v.AddRule("age", "min", 1)
	v.AddRule("email", "email")
	
	// can also
	v.StringRule("age", "required|int|min:1|max:99")
	v.StringRule("name", "required|minLen:7")
	v.StringRule("tags", "required|slice|minlen:1")
	// feat: support check sub-item in slice
	v.StringRule("tags.*", "required|string|min_len:7")

	// v.WithScenes(map[string]string{
	//	 "create": []string{"name", "email"},
	//	 "update": []string{"name"},
	// })
	
	r := v.ValidateR() // returns a *ValidResult, decoupled from v
	if r.IsOK() { // validate ok
		safeData := r.SafeData()
		// do something ...
	} else {
		fmt.Println(r.Errors) // all error messages
		fmt.Println(r.Errors.One()) // returns a random error message text
	}
}
```

> Tip: for struct validation, prefer the top-level `validate.Check(&u)` — it is
> stateless and pooled internally, and returns the same `*ValidResult`.

## Validate Request

If it is an HTTP request, you can quickly validate the data and pass the verification.
Then bind the secure data to the structure.

```go
package main

import (
	"fmt"
	"net/http"
	"time"

	"github.com/gookit/validate/v2"
)

// UserForm struct
type UserForm struct {
	Name     string
	Email    string
	Age      int
	CreateAt int
	Safe     int
	UpdateAt time.Time
	Code     string
}

func main()  {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		data, err := validate.FromRequest(r)
		if err != nil {
			panic(err)
		}

		v := data.Create()
		// setting rules
		v.FilterRule("age", "int") // convert value to int
		
		v.AddRule("name", "required")
		v.AddRule("name", "minLen", 7)
		v.AddRule("age", "max", 99)
		v.StringRule("code", `required|regex:\d{4,6}`)

		vr := v.ValidateR()
		if vr.IsOK() { // validate ok
			// safeData := vr.SafeData()
			userForm := &UserForm{}
			vr.BindSafeData(userForm)

			// do something ...
			fmt.Println(userForm.Name)
		} else {
			fmt.Println(vr.Errors) // all error messages
			fmt.Println(vr.Errors.One()) // returns a random error message text
		}
	})

	http.ListenAndServe(":8090", handler)
}
```

## Quick Method

Quick validate a struct (pooled internally, no manual lifecycle):

- `Check(structPtr any, scene ...string) *ValidResult` — recommended default for struct validation. Stateless from the caller's side, internally pooled. Returns a `*ValidResult` carrying the cleaned/safe data and bind helpers.
- `CheckErr(structPtr any, scene ...string) error` — **opt-in FAST entry** for "only need ok/err, no safe data / no binding". Pooled like `Check` but it **skips collecting safeData/filteredData** and does not build a `*ValidResult`, so it reaches fewer allocations (struct-valid: **0 allocs** vs `Check` 6, via RV-native end-to-end deboxing). Returns `nil` on pass, otherwise the first error.

```go
// fast pass/fail (e.g. middleware reject) — no cleaned data needed
if err := validate.CheckErr(&u); err != nil {
	return err
}

// need the cleaned data or BindStruct? use Check / ValidateR instead
r := validate.Check(&u)
if r.Fail() {
	return r.Err()
}
r.BindSafeData(&out)
```

> `CheckErr` is struct-only. For map data or programmatic rules, build a `Validation` (`New`/`Map` + `StringRule...`) and call `ValidateErr()`.

Quick create `Validation` instance.

- `New(data any, scene ...string) *Validation`
- `Request(r *http.Request) *Validation`
- `JSON(s string, scene ...string) *Validation`
- `Struct(s any, scene ...string) *Validation`
- `Map(m map[string]any, scene ...string) *Validation`

Quick create `DataFace` instance.

- `FromMap(m map[string]any) *MapData`
- `FromStruct(s any) (*StructData, error)`
- `FromJSON(s string) (*MapData, error)`
- `FromJSONBytes(bs []byte) (*MapData, error)`
- `FromURLValues(values url.Values) *FormData`
- `FromRequest(r *http.Request, maxMemoryLimit ...int64) (DataFace, error)`

> Create `Validation` from `DataFace`

```go
d := FromMap(map[string]any{"key": "val"})
v := d.Validation()
```

### Methods In Validation

- `func (v *Validation) Validate(scene ...string) bool` Do validating and return is success.
- `func (v *Validation) ValidateE(scene ...string) Errors` Do validating and return error.
- `func (v *Validation) ValidateR(scene ...string) *ValidResult` Validate and return a `ValidResult` decoupled from the instance.

> **Since v2.0, `Validation` keeps only the pass/fail + error face.** The safe-data /
> bind methods (`SafeData()` / `Safe()` / `SafeVal()` / `Filtered()` / `FilteredData()` /
> `BindSafeData()` / `BindStruct()`) moved to the result object `ValidResult`. Get one via
> `validate.Check(&u)` (recommended for structs, pooled) or `v.ValidateR()` (map/builder),
> then call e.g. `r.SafeData()` / `r.BindStruct(ptr)`. For pass/fail only, use
> `validate.CheckErr(structPtr any, scene ...string) error` (fewest allocations).

## More Usage

### Validate Error

`v.Errors` is map data, top key is field name, value is `map[string]string`.

```go
// do validating
if v.Validate() {
	return nil
}

// get errors
es := v.Errors

// check
es.Empty() // bool

// returns an random error, if no error returns nil
fmt.Println(v.Errors.OneError())
fmt.Println(v.Errors.ErrOrNil())

fmt.Println(v.Errors) // all error messages
fmt.Println(v.Errors.One()) // returns a random error message text
fmt.Println(v.Errors.Field("Name")) // returns error messages of the field 
```

**Encode to JSON**:

- `StopOnError=true`(default), will only one error

```json
{
    "field1": {
        "required": "error msg0"
    }
}
```

- if `StopOnError=false`, will get multi error

```json
{
    "field1": {
        "minLen": "error msg1",
        "required": "error msg0"
    },
    "field2": {
        "min": "error msg2"
    }
}
```

### Global Option

You can adjust some processing logic of the validator by changing the global option settings.

```go
// GlobalOption settings for validate
type GlobalOption struct {
	// FilterTag name in the struct tags.
	//
	// default: filter
	FilterTag string
	// ValidateTag in the struct tags.
	//
	// default: validate
	ValidateTag string
	// FieldTag the output field name in the struct tags.
	// it as placeholder on error message.
	//
	// default: json
	FieldTag string
	// LabelTag the display name in the struct tags.
	// use for define field translate name on error.
	//
	// default: label
	LabelTag string
	// MessageTag define error message for the field.
	//
	// default: message
	MessageTag string
	// StopOnError If true: An error occurs, it will cease to continue to verify
	StopOnError bool
	// SkipOnEmpty Skip check on field not exist or value is empty
	SkipOnEmpty bool
	// UpdateSource Whether to update source field value, useful for struct validate
	UpdateSource bool
	// CheckDefault Whether to validate the default value set by the user
	CheckDefault bool
	// CheckZero Whether validate the default zero value. (intX,uintX: 0, string: "")
	CheckZero bool
	// CheckSubOnParentMarked True: only collect sub-struct rule on current field has rule.
	CheckSubOnParentMarked bool
	// ValidatePrivateFields Whether to validate private fields or not, especially when inheriting other other structs.
	//
	//  type foo struct {
	//	  Field int `json:"field" validate:"required"`
	//  }
	//  type bar struct {
	//    foo // <-- validate this field
	//    Field2 int `json:"field2" validate:"required"`
	//  }
	//
	// default: false
	ValidatePrivateFields bool
}
```

**Usage**:

```go
// change global opts
validate.Config(func(opt *validate.GlobalOption) {
	opt.StopOnError = false
	opt.SkipOnEmpty = false
})
```

### Validating Private (Unexported fields)
By default, private fields are skipped. It is not uncommon to find code such as the following

```go
type foo struct {
	somefield int
}

type Bar struct {
	foo
	SomeOtherField string
}
```
In order to have `foo.somefield` validated, enable the behavior by setting `GlobalOption.ValidatePrivateFields` to `true`.

```go
validate.Config(func(opt *validate.GlobalOption) {
	opt.ValidatePrivateFields = true
})

```

### Custom Error Messages

- Register language messages

```go
import "github.com/gookit/validate/v2/locales/zhcn"

// for all Validation.
// NOTICE: must be registered before on validate.New(), it only need call at once.
zhcn.RegisterGlobal()

// ... ...

v := validate.New()

// only for current Validation
zhcn.Register(v)
```

- Manual add global messages

```go
validate.AddGlobalMessages(map[string]string{
    "minLength": "OO! {field} min length is %d",
})
```

- Add messages for current validation

```go
v := validate.New(map[string]any{
    "name": "inhere",
})
v.StringRule("name", "required|string|minLen:7|maxLen:15")

v.AddMessages(map[string]string{
    "minLength": "OO! {field} min length is %d",
    "name.minLen": "OO! username min length is %d",
})
```

- Use struct tags: `message, label`

```go
type UserForm struct {
    Name  string `validate:"required|minLen:7" label:"User Name"`
    Email string `validate:"email" message:"email is invalid" label:"User Email"`
}
```

- Use struct method `Messages()`

```go
// Messages you can custom validator error messages. 
func (f UserForm) Messages() map[string]string {
	return validate.MS{
		"required": "oh! the {field} is required",
		"Name.required": "message for special field",
	}
}
```

### Add Custom Validator

`validate` supports adding custom validators, and supports adding `global validator` and `temporary validator`.

- **Global Validator** is globally valid and can be used everywhere
- **Temporary Validator** added to the current validation instance, only the current validation is available
- Add verification method to the structure. How to use please see the structure verification example above

> Note: The validator method must return a `bool` to indicate whether the validation was successful.
> The first parameter is the corresponding field value. If there are additional parameters, they will be appended automatically.

#### Add Global Validator

You can add one or more custom validators at once.

```go
validate.AddValidator("myCheck0", func(val any) bool {
	// do validate val ...
	return true
})
validate.AddValidators(validate.M{
	"myCheck1": func(val any) bool {
		// do validate val ...
		return true
	},
})
```

#### Add Temporary Validator

Again, you can add one or more custom validators at once.

```go
v := validate.Struct(u)
v.AddValidator("myFunc3", func(val any) bool {
	// do validate val ...
	return true
})
v.AddValidators(validate.M{
	"myFunc4": func(val any) bool {
		// do validate val ...
		return true
	},
})
```

### Add Custom Filter

`validate` can also support adding custom filters, and supports adding `global filter` and `temporary filter`.

- **Global Filter** is globally valid and can be used everywhere
- **Temporary Filter** added to the current validation instance, only the current validation is available

> TIP: for filter func, we allow functions with 1 result or 2 results where the second is an error.

#### Add Global Filter

You can add one or more custom validators at once.

```go
package main

import "github.com/gookit/validate/v2"

func init() {
	validate.AddFilter("myToIntFilter0", func(val any) int {
		// do filtering val ...
		return 1
	})
	validate.AddFilters(validate.M{
		"myToIntFilter1": func(val any) (int, error) {
			// do filtering val ...
			return 1, nil
		},
	})
}
```

#### Add Temporary Filter

Again, you can add one or more custom filters at once.

```go
package main

import "github.com/gookit/validate/v2"

func main() {
	v := validate.New(&someStrcut{})

	v.AddFilter("myToIntFilter0", func(val any) int {
		// do filtering val ...
		return 1
	})
	v.AddFilters(validate.M{
		"myToIntFilter1": func(val any) (int, error) {
			// do filtering val ...
			return 1, nil
		},
	})
	// use the added filter
	v.FilterRule("field", "myToIntFilter0")
}
```

### Custom `required` validation

Allows a custom `required` validator to customize whether the validation is empty.

Frequently Asked Questions

What is validate?

validate is a Validation library for the Go programming language. Go package for data validation and filtering. support validate Map, Struct, Request(Form, JSON, url.Values, Uploaded Files) data and more features

How many GitHub stars does validate have?

validate has 1,166 GitHub stars in the directory's latest synchronization.

How do I install validate?

Install validate with the Go module system using `go get gookit/validate`. Check the repository for the current installation instructions.

What category does validate belong to?

validate is listed under Validation, specifically Validation.

← Back to Validation