Baike.dev
All toolsOnline toolsAI codingTrendingOpen sourceNewsSubmit
Log in
< Back to tools
V

validate

> 编程语言
Open source

⚔ Go package for data validation and filtering. support Map, Struct, Form data. Go通用的数据验证与过滤库,使用简单,内置大部分常用验证、过滤器,支持自定义验证器、自定义消息、字段翻译。

1.2K stars0 likes1 views
WebsiteGitHub

About

Validate

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

中文说明

  • 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
  • Many commonly used validators have been built in(> 70), see 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

v2.0: the module path is now github.com/gookit/validate/v2 (requires Go 1.21+). See the upgrade guide for migrating from v1.x.

Performance: see Benchmark comparison 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
…

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
…

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 for more on this behaviour change.

Validate Map

You can also validate a MAP data directly.

…

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.

…

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 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. However, note that the validator name must start with required, e.g. required_custom.

go
	type Data struct {
		Age  int    `validate:"required_custom" message:"age is required"`
		Name string `validate:"required"`
	}

	v := validate.New(&Data{
		Name: "tom",
		Age:  0,
	})

	v.AddValidator("required_custom", func(val any) bool {
		// do check value
		return false
	})

	ok := v.Validate()
	assert.False(t, ok)

…

go
import (
	"database/sql"
	"reflect"

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

// extract the underlying string from sql.NullString; nil when invalid (= empty)
validate.AddCustomType(func(field reflect.Value) any {
	ns := field.Interface().(sql.NullString)
	if !ns.Valid {
		return nil
	}
	return ns.String
}, sql.NullString{})

type Form struct {
	Name sql.NullString `validate:"required|minLen:3"`
}

v := validate.Struct(&Form{Name: sql.NullString{Valid: true, String: "inhere"}})
_ = v.Validate() // true: extracted "inhere" then checked by required|minLen:3

Pooled Factory (NewFactory)

When you validate large batches of the same type, an opt-in Factory reuses *Validation instances from a private pool to amortize the construction cost. The default behaviour and lifecycle of Struct / Map / New are unchanged — only callers who explicitly use a Factory get pooling.

Most callers should just use the top-level validate.Check(&u), which pools instances via a package pool automatically. Reach for a Factory

Issues· 0 open

View all issuesOpen on GitHub

No open issues yet, or sync has not completed.

> Tags

Gofiltergovalidatorvalidatevalidation

No comments yet. Be the first to share.

> Details

PublishedAug 1, 2026
UpdatedSep 17, 2026
Category编程语言
PricingOpen source

> Related tools

T
TypeScript
JavaScript 的超集,为前端与全栈提供静态类型
P
Python
通用编程语言,广泛用于 Web、数据与 AI
G
Go
Google 推出的简洁高效系统语言