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

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, suitable for bool, string, float64, nil, $ and ()
+ 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

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
    
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
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
Struct validation using tags

Govalid Use Govalid to validate structs. Documentation For full documentation see pkg.go.dev. Example package main import ( "fmt" "log" "strings"

Dec 6, 2022
Dec 28, 2022
Validate Golang request data with simple rules. Highly inspired by Laravel's request validation.
Validate Golang request data with simple rules. Highly inspired by Laravel's request validation.

Validate golang request data with simple rules. Highly inspired by Laravel's request validation. Installation Install the package using $ go get githu

Dec 29, 2022
Swagger builder and input validation for Go servers
Swagger builder and input validation for Go servers

crud A Swagger/OpenAPI builder and validation library for building HTTP/REST APIs. Heavily inspired by hapi and the hapi-swagger projects. No addition

Jan 5, 2023
Go package containing implementations of efficient encoding, decoding, and validation APIs.

encoding Go package containing implementations of encoders and decoders for various data formats. Motivation At Segment, we do a lot of marshaling and

Dec 25, 2022
Library providing opanapi3 and Go types for store/validation and transfer of ISO-4217, ISO-3166, and other types.

go-types This library has been created with the purpose to facilitate the store, validation, and transfer of Go ISO-3166/ISO-4217/timezones/emails/URL

Nov 9, 2022
Opinionated go to validation library

?? valeed Your opinionated go-to validation library. Struct tag-based. Validate here, validate there, validate everywhere. Sleek and simple validation

Jul 21, 2022
Simple module for validation inn control number

simple module for validation inn control number

Sep 4, 2022
Validator - Replace the validation framework used by gin

validator Replace the validation framework used by gin replace mod:replace githu

Jan 18, 2022
:balloon: A lightweight struct validator for Go

gody Go versions supported Installation go get github.com/guiferpa/gody/v2 Usage package main import ( "encoding/json" "fmt" "net/http"

Nov 19, 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