An interesting go struct tag expression syntax for field validation, etc.

go-tagexpr report card GoDoc

An interesting go struct tag expression syntax for field validation, etc.

Usage

  • Validator: A powerful validator that supports struct tag expression

  • Binding: A powerful HTTP request parameters binder that supports struct tag expression

Feature

  • Support for a variety of common operator
  • Support for accessing arrays, slices, members of the dictionary
  • Support access to any field in the current structure
  • Support access to nested fields, non-exported fields, etc.
  • Support registers function expression
  • Built-in len, sprintf, regexp functions
  • Support single mode and multiple mode to define expression
  • Parameter check subpackage
  • Use offset pointers to directly take values, better performance
  • Required go version ≥1.9

Example

=100"` B string `tagexpr:"len($)>1 && regexp('^\\w*$')"` C bool `tagexpr:"expr1:(f.g)$>0 && $; expr2:'C must be true when T.f.g>0'"` d []string `tagexpr:"@:len($)>0 && $[0]=='D'; msg:sprintf('invalid d: %v',$)"` e map[string]int `tagexpr:"len($)==$['len']"` e2 map[string]*int `tagexpr:"len($)==$['len']"` f struct { g int `tagexpr:"$"` } } vm := tagexpr.New("tagexpr") t := &T{ A: 107, B: "abc", C: true, d: []string{"x", "y"}, e: map[string]int{"len": 1}, e2: map[string]*int{"len": new(int)}, f: struct { g int `tagexpr:"$"` }{1}, } tagExpr, err := vm.Run(t) if err != nil { panic(err) } fmt.Println(tagExpr.Eval("A")) fmt.Println(tagExpr.Eval("B")) fmt.Println(tagExpr.Eval("C@expr1")) fmt.Println(tagExpr.Eval("C@expr2")) if !tagExpr.Eval("d").(bool) { fmt.Println(tagExpr.Eval("d@msg")) } fmt.Println(tagExpr.Eval("e")) fmt.Println(tagExpr.Eval("e2")) fmt.Println(tagExpr.Eval("f.g")) // Output: // true // true // true // C must be true when T.f.g>0 // invalid d: [x y] // true // false // 1 } ">
package tagexpr_test

import (
	"fmt"

	tagexpr "github.com/bytedance/go-tagexpr/v2"
)

func Example() {
	type T struct {
		A  int             `tagexpr:"$<0||$>=100"`
		B  string          `tagexpr:"len($)>1 && regexp('^\\w*$')"`
		C  bool            `tagexpr:"expr1:(f.g)$>0 && $; expr2:'C must be true when T.f.g>0'"`
		d  []string        `tagexpr:"@:len($)>0 && $[0]=='D'; msg:sprintf('invalid d: %v',$)"`
		e  map[string]int  `tagexpr:"len($)==$['len']"`
		e2 map[string]*int `tagexpr:"len($)==$['len']"`
		f  struct {
			g int `tagexpr:"$"`
		}
	}

	vm := tagexpr.New("tagexpr")
	t := &T{
		A:  107,
		B:  "abc",
		C:  true,
		d:  []string{"x", "y"},
		e:  map[string]int{"len": 1},
		e2: map[string]*int{"len": new(int)},
		f: struct {
			g int `tagexpr:"$"`
		}{1},
	}

	tagExpr, err := vm.Run(t)
	if err != nil {
		panic(err)
	}

	fmt.Println(tagExpr.Eval("A"))
	fmt.Println(tagExpr.Eval("B"))
	fmt.Println(tagExpr.Eval("C@expr1"))
	fmt.Println(tagExpr.Eval("C@expr2"))
	if !tagExpr.Eval("d").(bool) {
		fmt.Println(tagExpr.Eval("d@msg"))
	}
	fmt.Println(tagExpr.Eval("e"))
	fmt.Println(tagExpr.Eval("e2"))
	fmt.Println(tagExpr.Eval("f.g"))

	// Output:
	// true
	// true
	// true
	// C must be true when T.f.g>0
	// invalid d: [x y]
	// true
	// false
	// 1
}

Syntax

Struct tag syntax spec:

type T struct {
	// Single model
    Field1 T1 `tagName:"expression"`
	// Multiple model
    Field2 T2 `tagName:"exprName:expression; [exprName2:expression2;]..."`
	// Omit it
    Field3 T3 `tagName:"-"`
    // Omit it when it is nil
    Field4 T4 `tagName:"?"`
    ...
}

NOTE: The exprName under the same struct field cannot be the same!

Operator or Operand Explain
true false boolean
0 0.0 float64 "0"
'' String
\\' Escape ' delims in string
\" Escape " delims in string
nil nil, undefined
! not
+ Digital addition or string splicing
- Digital subtraction or negative
* Digital multiplication
/ Digital division
% division remainder, as: float64(int64(a)%int64(b))
== eq
!= ne
> gt
>= ge
< lt
<= le
&& Logic and
|| Logic or
() Expression group
(X)$ Struct field value named X
(X.Y)$ Struct field value named X.Y
$ Shorthand for (X)$, omit (X) to indicate current struct field value
(X)$['A'] Map value with key A or struct A sub-field in the struct field X
(X)$[0] The 0th element or sub-field of the struct field X(type: map, slice, array, struct)
len((X)$) Built-in function len, the length of struct field X
mblen((X)$) the length of string field X (character number)
regexp('^\\w*$', (X)$) Regular match the struct field X, return boolean
regexp('^\\w*$') Regular match the current struct field, return boolean
sprintf('X value: %v', (X)$) fmt.Sprintf, format the value of struct field X
range(KvExpr, forEachExpr) Iterate over an array, slice, or dictionary
- #k is the element key var
- #v is the element value var
- ## is the number of elements
- e.g. example

Operator priority(high -> low):

  • () ! bool float64 string nil
  • * / %
  • + -
  • < <= > >=
  • == !=
  • &&
  • ||

Field Selector

field_lv1.field_lv2...field_lvn

Expression Selector

  • If expression is single model or exprName is @:
field_lv1.field_lv2...field_lvn
  • If expression is multiple model and exprName is not @:
field_lv1.field_lv2...field_lvn@exprName

Benchmark

goos: darwin
goarch: amd64
pkg: github.com/bytedance/go-tagexpr
BenchmarkTagExpr-4   	10000000	       148 ns/op	      32 B/op	       3 allocs/op
BenchmarkReflect-4   	10000000	       182 ns/op	      16 B/op	       2 allocs/op
PASS

Go to test code

Comments
  • query: 1. how to validate slice elements? 2.how to validate nested struct?

    query: 1. how to validate slice elements? 2.how to validate nested struct?

    I have one question and one improvement suggestion, the scenario is as below:

    AssetListRequestV1 is the request struct

    1. for AssetPlatform field, the validate rule is: all the elements in it should be "1" or "2" or "3" how do I write the validation tag?
    	// asset list request
    	AssetListRequestV1 struct {
    		AssetPlatform   []string
    		AmountLow       float64 `vd:"$>=0"`
    		AmountHigh      float64 `vd:"$>=(AmountLow)$"`
    		AprLow          int     `vd:"$>=0 && $<=100"`
    		AprHigh         int     `vd:"$>=0 && $<=100 && $>=(AprLow)$"`
    		RatingLow       int     `vd:"$>=0 && $<=100"`
    		RatingHigh      int     `vd:"$>=0 && $<=100 && $>=(RatingLow)$"`
    		TradeCreditLow  int     `vd:"$>=0 && $<=100"`
    		TradeCreditHigh int     `vd:"$>=0 && $<=100 && $>=(TradeCreditLow)$"`
    		OrderCond       []OrderCond
    		Page            int `vd:"$>=1"`
    		RowCount        int `vd:"$>=1"`
    	}
    
    	OrderCond struct {
    		OrderField string `vd:"$=='asset_platform' || $=='asset_identifier' || $=='update_ts' || $=='debtor' || $=='amount' || $=='apr' || $=='due_dt' || $=='rating' || $=='trade_credit'"`
    		Order      string `vd:"$=='desc' || $=='asc'"`
    	}
    
    1. OrderCond is the sub field of AssetListRequestV1, although I have write validation tag in its own struct, but it will not check if I wirte code like this
    var vd = validator.New("vd")
    func ListAssetDetail(c *gin.Context) {
    	// get req
    	req := new(AssetListRequestV1)
    	if err := c.Bind(req); err != nil {
    		ResponseErr(c, ErrInvalidParam, err.Error())
    		return
    	}
    
    	// input check
    	if err := vd.Validate(req); err != nil {
    		ResponseErr(c, ErrRequestValidationNotPass, err.Error())
    		return
    	}
    .........
    }
    

    actually, I need to range the nested struct by myself

    var vd = validator.New("vd")
    
    func ListAssetDetail(c *gin.Context) {
    	// get req
    	req := new(AssetListRequestV1)
    	if err := c.Bind(req); err != nil {
    		ResponseErr(c, ErrInvalidParam, err.Error())
    		return
    	}
    
    	// input check
    	if err := vd.Validate(req); err != nil {
    		ResponseErr(c, ErrRequestValidationNotPass, err.Error())
    		return
    	}
    
    	for _, cond := range req.OrderCond {
    		if err := vd.Validate(&cond); err != nil {
    			ResponseErr(c, ErrRequestValidationNotPass, err.Error())
    			return
    		}
    	}
    
    .......
    
    }
    

    I think it can be improved @henrylee2cn

  • 自定义函数的逻辑运算问题

    自定义函数的逻辑运算问题

    type TStruct struct {
    	TOk string `vd:"gt($,'0') && gt($, '1')" json:"t_ok"`
    	//TFail string `vd:"gt($,'0')" json:"t_fail"`
    }
    
    func TInit() {
    	validator.RegFunc("gt", func(args ...interface{}) error {
    		return errors.New("force error")
    	})
    }
    func Test_tagexpr(t *testing.T) {
    	TInit()
    	fmt.Printf("%+v\n", validator.Validate(&TStruct{TOk: "1" /*TFail: "1"*/}))
    }
    

    如上代码 自定义了“gt”函数,TFail字段单独使用gt函数,validate会报错,符合预期; 但是TOk字段,对两个gt函数执行了逻辑运算,validate会通过,不符合预期。

  • Renamed third-party package from `henrylee2cn` caused error

    Renamed third-party package from `henrylee2cn` caused error

    When trying to install the newest version, I got the error below:

    go get: github.com/henrylee2cn/[email protected] updating to
            github.com/henrylee2cn/[email protected]: parsing go.mod:
            module declares its path as: github.com/andeya/goutil
                    but was required as: github.com/henrylee2cn/goutil
    
  • chore(deps): bump github.com/tidwall/gjson from 1.6.0 to 1.9.3

    chore(deps): bump github.com/tidwall/gjson from 1.6.0 to 1.9.3

    ⚠️ Dependabot is rebasing this PR ⚠️

    Rebasing might not happen immediately, so don't worry if this takes some time.

    Note: if you make any changes to this PR yourself, they will take precedence over the rebase.


    Bumps github.com/tidwall/gjson from 1.6.0 to 1.9.3.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

  • 在 vd 的时候 msg 里如果包含单引号会产生不可预料的错误

    在 vd 的时候 msg 里如果包含单引号会产生不可预料的错误

    如在

    `query:"profiling_id" vd:"@:len($)==32; msg:'profiling_id's length is invalid'"`
    

    这样的句子里,msg 里包含的单引号会使整个vd失效而无法产生正确结果; 如果将msg 里的单引号转义 ',会产生一个更奇葩的效果就是服务第一次的验证会成功,而之后的验证都会失效。 以及同学有没有内部的联系方式方便讨论呀?

  • Custom type supported? Like decimal.

    Custom type supported? Like decimal.

    Test case

    import (
    	"fmt"
    	vd "github.com/bytedance/go-tagexpr/validator"
    	"github.com/shopspring/decimal"
    )
    
    func main() {
    		p := struct {
    			Price decimal.Decimal `vd:"$>0"`
    		}{
    			Price: decimal.NewFromFloat(1.00),
    		}
    		fmt.Println(vd.Validate(p))
    }
    

    would result

    invalid parameter: Price
    
  • go mod 问题

    go mod 问题

    我把demo copy到本地尝试运行,但是因为go mod 下载包的原因而不不能通过编译,

    我用的是go 12.4 GO111MODULE=on GOPROXY=https://athens.azurefd.net

    tagexpr 使用了包 github.com/henrylee2cn/goutil/tpack 这个包用 go mod tidy 下载不下来

  • 建议新增CheckAll函数

    建议新增CheckAll函数

    想对一个结构体检查,只要有一个参数不在预期就返回false 伪代码如下

    
     type T struct {
            A  int             `tagexpr:"$<0||$>=100"`
            B  string          `tagexpr:"len($)>1 && regexp('^\\w*$')"`
            C  bool            `tagexpr:"{expr1:(f.g)$>0 && $}{expr2:'C must be true when T.f.g>0'}"`
            d  []string        `tagexpr:"{@:len($)>0 && $[0]=='D'} {msg:sprintf('invalid d: %v',$)}"`
            e  map[string]int  `tagexpr:"len($)==$['len']"`
            e2 map[string]*int `tagexpr:"len($)==$['len']"`
            f  struct {
                g int `tagexpr:"$"`
            }
        }   
    
        vm := tagexpr.New("tagexpr")
        err := vm.WarmUp(new(T))
        if err != nil {
            panic(err)
        }   
    
        t := &T{ 
            A:  107,
            B:  "abc",
            C:  true,
            d:  []string{"x", "y"},
            e:  map[string]int{"len": 1}, 
            e2: map[string]*int{"len": new(int)},
            f: struct {
                g int `tagexpr:"$"`
            }{1},
        }   
    
        tagExpr, err := vm.Run(t)
        if err != nil {
            panic(err)
        }   
    
        // 看我 
        b := tagExpr.CheckAll(t)
        if !b {
            fmt.Printf("invalid argument\n")
        }
    
    
  • 自定义 json-unmarshal 函数设置为实例级别

    自定义 json-unmarshal 函数设置为实例级别

    你好!

    var (
    	jsonUnmarshalFunc func(data []byte, v interface{}) error
    )
    
    // ResetJSONUnmarshaler reset the JSON Unmarshal function.
    // NOTE: verifyingRequired is true if the required tag is supported.
    func ResetJSONUnmarshaler(fn JSONUnmarshaler) {
    	jsonUnmarshalFunc = fn
    }
    

    现在 jsonUnmarshalFunc 是全局变量,ResetJSONUnmarshaler 是全局影响的函数。

    可否将 jsonUnmarshalFunc 绑定到 Binding 结构体上,然后 ResetJSONUnmarshaler 函数,去修改 defaultBinding 实例?

    这样的话,可以控制只影响一个实例的 unmarshal 效果。

    如果可以的话,我可以来提供这个修改。谢谢。

  • feat: support stop semantics

    feat: support stop semantics

    close #34

    If a custom function returns ErrStop, the field checks after this field where in the same struct are stopped.

    Update: Use io.ErrUnexpectedEOF in the validator to indicate an error in the validation.

    Hi, since io.EOF is used in validator, I use io.EOF to represent stopping the validation of the current struct fields. Please help to see if this way is possible

  • The json body parameter does not take effect when default tag is set

    The json body parameter does not take effect when default tag is set

    当入参填写了 default tag 并且没有 json tag 的时候,无论 body 中填什么值,都会被 default 值覆盖。 body 入参的定义如下 type GetItemRequest struct { Content string thrift:"Content,1,required" default:"hello" } 此时,curl 请求 curl 'http://localhost:6791?Action=GetItem'
    --header 'Content-Type: application/json'
    --data-raw '{ "Content": "123", }' 后,Content 值依然为 hello

    猜测原因: https://github.com/bytedance/go-tagexpr/blob/873eca54c6826ba829b91e813a5b4681bdd9b41d/binding/bind.go#L169 这个地方先把 body unmarshal 到 Req 中,在没有打 json tag 而只打了 default tag 的情况下,就会执行 https://github.com/bytedance/go-tagexpr/blob/873eca54c6826ba829b91e813a5b4681bdd9b41d/binding/bind.go#L213 从而又把 default 值覆盖到了已有的值中

  • bindStruct中在for循环里面进行header取数,会有内存和性能问题,可以统一放到外部处理

    bindStruct中在for循环里面进行header取数,会有内存和性能问题,可以统一放到外部处理

    func (b *Binding) bindStruct(structPointer interface{}, structValue reflect.Value, req Request, pathParams PathParams) (hasVd bool, err error) { recv, err := b.getOrPrepareReceiver(structValue) if err != nil { return }

    expr, err := b.vd.VM().Run(structValue)
    if err != nil {
    	return
    }
    
    bodyCodec, bodyBytes, err := recv.getBodyInfo(req)
    if len(bodyBytes) > 0 {
    	err = b.prebindBody(structPointer, structValue, bodyCodec, bodyBytes)
    }
    if err != nil {
    	return
    }
    bodyString := ameda.UnsafeBytesToString(bodyBytes)
    postForm, err := req.GetPostForm()
    if err != nil {
    	return
    }
    var fileHeaders map[string][]*multipart.FileHeader
    if _req, ok := req.(requestWithFileHeader); ok {
    	fileHeaders, err = _req.GetFileHeaders()
    	if err != nil {
    		return
    	}
    }
    queryValues := recv.getQuery(req)
    cookies := recv.getCookies(req)
    headers := req.GetHeader()
    
    for _, param := range recv.params {
    	for i, info := range param.tagInfos {
    		var found bool
    		switch info.paramIn {
    		case raw_body:
    			err = param.bindRawBody(info, expr, bodyBytes)
    			found = err == nil
    		case path:
    			found, err = param.bindPath(info, expr, pathParams)
    		case query:
    			found, err = param.bindQuery(info, expr, queryValues)
    		case cookie:
    			found, err = param.bindCookie(info, expr, cookies)
    		case header:
    			found, err = param.bindHeader(info, expr, headers)
    		case form, json, protobuf:
    			if info.paramIn == in(bodyCodec) {
    				found, err = param.bindOrRequireBody(info, expr, bodyCodec, bodyString, postForm, fileHeaders,
    					recv.hasDefaultVal)
    			} else if info.required {
    				found = false
    				err = info.requiredError
    			}
    		case default_val:
    			found, err = param.bindDefaultVal(expr, param.defaultVal)
    		}
    		if found && err == nil {
    			break
    		}
    		if (found || i == len(param.tagInfos)-1) && err != nil {
    			return recv.hasVd, err
    		}
    	}
    }
    return recv.hasVd, nil
    

    }

  • validator couldn't distinguish whether a slice is nil or empty

    validator couldn't distinguish whether a slice is nil or empty

    func TestSlice(t *testing.T) {
      assert := assert.New(t)
    
      type Request struct {
        IDs []int `vd:"$ == nil || len($) > 0"`
      }
    
      req := &Request{}
      assert.Nil(req.IDs)
    
      err := validator.Validate(req)
      assert.Nil(err) // this assert would fail
    }
    
  • binding对 json 传递为null的struct字段做了struct内各字段的tag检查

    binding对 json 传递为null的struct字段做了struct内各字段的tag检查

    type Address struct{
            City  string       `form:"city,required" json:"city,required" query:"city,required"`
    } 
    
    type User struct{
            Name      string      `form:"name" json:"name,required" query:"name"`
            Address  *Address   `form:"address" json:"address,omitempty" query:"address"`
    }
    
    // request body 为json {"name":"Jack", "address":null}
    var user model.User
    err = binding.BindAndValidate(c, &user)
    

    预期user能正常的绑定,user.Address == nil,实际上返回错误提示 binding: expr_path=address.city, cause=missing required parameter

  • Supporting different JSON tag

    Supporting different JSON tag

    Hi

    Is it possible to support custom JSON tag for binding data? As sometime for the same data, we will want to support snake case and camel case for the same field.

    Example:

    type Person struct {
    	DateOfBirth string `json:"dateOfBirth" sjson:"date_of_birth"`
    }
    
  • binding.Error 和 validator.Error 行为不一致

    binding.Error 和 validator.Error 行为不一致

    当使用msg自定义错误信息时 validator的Error的行为是,如果有自定义错误信息就只返回自定义信息

    // Error implements error interface.
    func (e *Error) Error() string {
    	if e.Msg != "" {
    		return e.Msg
    	}
    	return "invalid parameter: " + e.FailPath
    }
    

    而binding的Error却会有其他附加信息

    func (e *Error) Error() string {
    	if e.Msg != "" {
    		return e.ErrType + ": expr_path=" + e.FailField + ", cause=" + e.Msg
    	}
    	return e.ErrType + ": expr_path=" + e.FailField + ", cause=invalid"
    }
    

    建议,

    1. 两者的行为应该一致。
    2. 可以考虑在e.Msg支持占位符,由用户自己决定想要的错误信息格式。如
    placeholders := map[string]string {"{{ ErrType }}":e.ErrType, "{{ FailField  }}":e..FailField }
    msg := e.Msg
    
    for k, v := range placeholders{
        msg = strings.Replace(msg, k, v)
    }
    
    return msg
    
Convert arbitrary formats to Go Struct (including json, toml, yaml, etc.)

go2struct Convert arbitrary formats to Go Struct (including json, toml, yaml, etc.) Installation Run the following command under your project: go get

Nov 15, 2022
A Go implementation of the core algorithm in paper

Boolean Expression Indexer Go library A Go implementation of the core algorithm in paper <Indexing Boolean Expression>, which already supports the fol

Dec 26, 2022
Exp-tree: go library for parsing expression tree

Vinshop expression tree Exp-tree is go library for parsing expression tree Installation go get -u github.com/vinshop/exp-tree Quick start Format Expre

May 11, 2022
Golang string comparison and edit distance algorithms library, featuring : Levenshtein, LCS, Hamming, Damerau levenshtein (OSA and Adjacent transpositions algorithms), Jaro-Winkler, Cosine, etc...

Go-edlib : Edit distance and string comparison library Golang string comparison and edit distance algorithms library featuring : Levenshtein, LCS, Ham

Dec 20, 2022
Generic types that are missing from Go, including sets, trees, sorted lists, etc.

go-typ Generic types that are missing from Go, including sets, trees, sorted lists, etc. All code is implemented with 0 dependencies and in pure Go co

Dec 4, 2022
Converts PDF, DOC, DOCX, XML, HTML, RTF, etc to plain text

docconv A Go wrapper library to convert PDF, DOC, DOCX, XML, HTML, RTF, ODT, Pages documents and images (see optional dependencies below) to plain tex

Jan 5, 2023
A faster method to get elements from an interface (Struct or Slice type) for Go.

A faster method to get elements from an interface (Struct or Slice type) for Go.

May 13, 2022
Convert json string to Golang struct

json-to-go-cli Convert json string to Golang struct How to install git clone https://github.com/tiancheng92/json-to-go-cli.git cd json-to-go-cli go bu

May 10, 2022
GoStruct2Table - format your struct like a table.

GoStruct2Table format your struct like a table. Installing $ go get -u -v github.com/runningzyp/GoStruct2Table Simple Example import parser "github.c

Aug 15, 2022
An interesting go struct tag expression syntax for field validation, etc.

An interesting go struct tag expression syntax for field validation, etc.

Jan 8, 2023
:100:Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving

Package validator Package validator implements value validations for structs and individual fields based on tags. It has the following unique features

Jan 1, 2023
💯 Go Struct and Field validation, including Cross Field, Cross Struct, Map, Slice and Array diving

Package validator implements value validations for structs and individual fields based on tags.

Nov 9, 2022
Golang parameter validation, which can replace go-playground/validator, includes ncluding Cross Field, Map, Slice and Array diving, provides readable,flexible, configurable validation.
Golang parameter validation, which can replace go-playground/validator, includes ncluding Cross Field, Map, Slice and Array diving, provides readable,flexible, configurable validation.

Checker 中文版本 Checker is a parameter validation package, can be use in struct/non-struct validation, including cross field validation in struct, elemen

Dec 16, 2022
An idiomatic Go (golang) validation package. Supports configurable and extensible validation rules (validators) using normal language constructs instead of error-prone struct tags.

ozzo-validation Description ozzo-validation is a Go package that provides configurable and extensible data validation capabilities. It has the followi

Jan 7, 2023
Just a playground with some interesting concepts like pipelines aka middleware, handleFuncs, request validations etc. Check it out.

Pipeline a.k.a middleware in Go Just a playground with some interesting concepts like pipelines aka middleware, handleFuncs, request validations etc.

Dec 9, 2021
Gin Middleware to extract json tag value from playground validator's errors validation

Json Tag Extractor for Go-Playground Validator This is Gin Middleware that aim to extract json tag and than store it to FieldError.Field() object. Ins

Jan 14, 2022
☄ The golang convenient converter supports Database to Struct, SQL to Struct, and JSON to Struct.
☄ The golang convenient converter supports Database to Struct, SQL to Struct, and JSON to Struct.

Gormat - Cross platform gopher tool The golang convenient converter supports Database to Struct, SQL to Struct, and JSON to Struct. 中文说明 Features Data

Dec 20, 2022
Go tool to modify struct field tags
Go tool to modify struct field tags

Go tool to modify/update field tags in structs. gomodifytags makes it easy to update, add or delete the tags in a struct field. You can easily add new tags, update existing tags (such as appending a new key, i.e: db, xml, etc..) or remove existing tags

Jan 1, 2023
structslop is a static analyzer for Go that recommends struct field rearrangements to provide for maximum space/allocation efficiency.

structslop Package structslop defines an Analyzer that checks struct can be re-arranged fields to get optimal struct size.

Dec 28, 2022
Go linter to check the struct literal to use field name

Structfield Find struct literals using non-labeled fields. The structfield analysis reports the usage of struct literal using non-labeled fields more

Aug 23, 2021