11---
22title : " Binding and validate"
3- date : 2022-06-21
3+ date : 2025-12-08
44weight : 8
55keywords :
66 ["Binding and validate", "go-tagexpr", "tag", "Parameter binding precedence"]
@@ -129,7 +129,7 @@ type TagRequiredReq struct {
129129
130130### Customise binder
131131
132- > hertz version >= v0.7.0 support
132+ > hertz version >= v0.10.3 support
133133
134134You need to implement the Binder interface and inject it into the hertz engine in a configurable way.
135135
@@ -138,13 +138,13 @@ type Binder interface {
138138 Name () string // The name of the binder.
139139 // The following are the various binding methods
140140 Bind (*protocol.Request , interface {}, param.Params ) error
141- BindAndValidate (*protocol.Request , interface {}, param.Params ) error
142141 BindQuery (*protocol.Request , interface {}) error
143142 BindHeader (*protocol.Request , interface {}) error
144143 BindPath (*protocol.Request , interface {}, param.Params ) error
145144 BindForm (*protocol.Request , interface {}) error
146145 BindJSON (*protocol.Request , interface {}) error
147146 BindProtobuf (*protocol.Request , interface {}) error
147+ Validate (*protocol.Request , interface {}) error
148148}
149149```
150150
@@ -170,10 +170,6 @@ func (m *mockBinder) Bind(request *protocol.Request, i interface{}, params param
170170 return nil
171171}
172172
173- func (m *mockBinder ) BindAndValidate (request *protocol .Request , i interface {}, params param .Params ) error {
174- return fmt.Errorf (" test binder" )
175- }
176-
177173func (m *mockBinder ) BindQuery (request *protocol .Request , i interface {}) error {
178174 return nil
179175}
@@ -198,15 +194,42 @@ func (m *mockBinder) BindProtobuf(request *protocol.Request, i interface{}) erro
198194 return nil
199195}
200196
197+ func (m *mockBinder ) Validate (request *protocol .Request , i interface {}) error {
198+ return nil
199+ }
200+
201201```
202202
203203Currently expanded binders:
204204
205+ > ⚠️ Note: The ` hertz-contrib/binding ` middleware is now deprecated.
206+ > Users are recommended to use built-in functionality in Hertz or their own custom binder.
207+
205208- bytedance/go-tagexpr: https://github.com/hertz-contrib/binding/tree/main/go_tagexpr (binding library used before refactoring)
206209
207210### Custom validator
208211
209- > Supported by hertz version >= v0.7.0.
212+ > Supported by hertz version >= v0.10.3.
213+
214+ ``` go
215+ import (
216+ " github.com/go-playground/validator/v10"
217+ )
218+
219+ func main () {
220+ vd := validator.New (validator.WithRequiredStructEnabled ())
221+ h := server.Default (server.WithHostPorts (" 127.0.0.1:8080" ),
222+ server.WithCustomValidatorFunc (func (_ *protocol.Request , req any) error {
223+ return vd.Struct (req)
224+ }),
225+ )
226+ h.Spin ()
227+ }
228+ ```
229+
230+ #### Custom validator (Deprecated)
231+
232+ > Supported by Hertz versions 0.7.0 to 0.10.2.
210233
211234You need to implement the Validator interface and inject it into the hertz engine in a configurable way.
212235
@@ -247,13 +270,16 @@ func (m *mockValidator) ValidateTag() string {
247270
248271Currently expanded validators:
249272
273+ > ⚠️ Note: The ` hertz-contrib/binding ` middleware is now deprecated.
274+ > Users are recommended to use the built-in functionality in Hertz. If custom validation is required, users can use the validator from [ go-playground/validator] ( https://github.com/go-playground/validator ) .
275+
250276- go-playground/validator: https://github.com/hertz-contrib/binding/tree/main/go_playground
251277
252278### Customize the error of binding and validation
253279
254280When an error occurs in the binding parameter and the parameter validation fails, user can customize the Error([ demo] ( https://github.com/cloudwego/hertz-examples/tree/main/binding/custom_error ) )For example:
255281The user can customise the content of the Error in case of binding parameter errors and parameter validation failures, using the following method:<br >
256- ** hertz version >= v0.7.0 **
282+ ** hertz version >= v0.10.3 **
257283
258284> Custom bind errors are not supported at this time.
259285
@@ -262,6 +288,77 @@ Custom validate error:
262288``` go
263289package main
264290
291+ import (
292+ " context"
293+ " fmt"
294+
295+ " github.com/cloudwego/hertz/pkg/app"
296+ " github.com/cloudwego/hertz/pkg/app/server"
297+ " github.com/cloudwego/hertz/pkg/protocol"
298+ " github.com/go-playground/validator/v10"
299+ )
300+
301+ type User struct {
302+ Name string ` form:"name" validate:"required"`
303+ Age uint8 ` form:"age" validate:"gte=0,lte=130"`
304+ Email string ` form:"email" validate:"required,email"`
305+ }
306+
307+ type ValidateError struct {
308+ ErrType , FailField , Msg string
309+ }
310+
311+ func (e *ValidateError ) Error () string {
312+ if e.Msg != " " {
313+ return e.ErrType + " : expr_path=" + e.FailField + " , cause=" + e.Msg
314+ }
315+ return e.ErrType + " : expr_path=" + e.FailField + " , cause=invalid"
316+ }
317+
318+ func main () {
319+ v := validator.New (validator.WithRequiredStructEnabled ())
320+
321+ h := server.Default (
322+ server.WithHostPorts (" 127.0.0.1:8080" ),
323+ server.WithCustomValidatorFunc (func (_ *protocol.Request , req any) error {
324+ err := v.Struct (req)
325+ if err == nil {
326+ return nil
327+ }
328+
329+ if ve , ok := err.(validator.ValidationErrors ); ok {
330+ fe := ve[0 ]
331+
332+ return &ValidateError{
333+ ErrType: " validateErr" ,
334+ FailField: fe.Field (),
335+ Msg: fe.Tag (),
336+ }
337+ }
338+
339+ return err
340+ }),
341+ )
342+
343+ h.GET (" /bind" , func (ctx context.Context , c *app.RequestContext ) {
344+ var user User
345+ err := c.BindAndValidate (&user)
346+ if err != nil {
347+ fmt.Println (" CUSTOM:" , err.Error ())
348+ return
349+ }
350+ fmt.Println (" OK:" , user)
351+ })
352+
353+ h.Spin ()
354+ }
355+ ```
356+
357+ ** hertz versions 0.7.0 to 0.10.2** <br >
358+
359+ ``` go
360+ package main
361+
265362import (
266363 " github.com/cloudwego/hertz/pkg/app/server/binding"
267364 " github.com/cloudwego/hertz/pkg/app/server"
@@ -356,34 +453,6 @@ func init() {
356453In the parameter binding, for some special types, when the default behavior can not meet the demand, you can use the custom type resolution to solve the problem, the use of the following: <br >
357454** hertz version >= v0.7.0** <br >
358455
359- ``` go
360- import " github.com/cloudwego/hertz/pkg/app/server/binding"
361-
362- type Nested struct {
363- B string
364- C string
365- }
366-
367- type TestBind struct {
368- A Nested ` query:"a,required"`
369- }
370-
371- func init () {
372- binding.MustRegTypeUnmarshal (reflect.TypeOf (Nested{}), func (v string , emptyAsZero bool ) (reflect.Value , error ) {
373- if v == " " && emptyAsZero {
374- return reflect.ValueOf (Nested{}), nil
375- }
376- val := Nested{
377- B: v[:5 ],
378- C: v[5 :],
379- }
380- return reflect.ValueOf (val), nil
381- })
382- }
383- ```
384-
385- ### Customize the validation function
386-
387456``` go
388457package main
389458
@@ -402,7 +471,7 @@ type TestBind struct {
402471}
403472
404473func main () {
405- bindConfig := & binding.BindConfig {}
474+ bindConfig := binding.NewBindConfig ()
406475 // After v0.7.0 refactoring, on the basis of the original increase in the request content and routing parameters,
407476 // which can be more flexible for the user to customise the type of parsing
408477 // Note: Only after a tag is successfully matched will the custom logic go through.
@@ -456,8 +525,55 @@ func init() {
456525
457526### Custom validation function
458527
459- Complex validation logic can be implemented in the ` vd ` annotation by registering a custom validation function:<br >
460- ** hertz version >= v0.7.0** <br >
528+ Complex validation logic can be implemented in the ` validate ` annotation by registering a custom validation function:<br >
529+ ** hertz version >= v0.10.3** <br >
530+
531+ ``` go
532+ package main
533+
534+ import (
535+ " context"
536+ " fmt"
537+
538+ " github.com/cloudwego/hertz/pkg/app"
539+ " github.com/cloudwego/hertz/pkg/app/server"
540+ " github.com/cloudwego/hertz/pkg/app/server/binding"
541+ " github.com/cloudwego/hertz/pkg/protocol"
542+ " github.com/go-playground/validator/v10"
543+ )
544+
545+ type Req struct {
546+ A string ` query:"a" validate:"test"`
547+ }
548+
549+ func main () {
550+ vd := validator.New (validator.WithRequiredStructEnabled ())
551+
552+ vd.RegisterValidation (" test" , func (fl validator.FieldLevel ) bool {
553+ return fl.Field ().String () != " 123"
554+ })
555+
556+ h := server.Default (
557+ server.WithHostPorts (" 127.0.0.1:8080" ),
558+ server.WithCustomValidatorFunc (func (_ *protocol.Request , req any) error {
559+ return vd.Struct (req)
560+ }),
561+ )
562+
563+ h.GET (" /test" , func (ctx context.Context , c *app.RequestContext ) {
564+ var r Req
565+ if err := c.BindAndValidate (&r); err != nil {
566+ fmt.Println (" VALIDATION ERROR:" , err.Error ())
567+ return
568+ }
569+ fmt.Println (" OK:" , r)
570+ })
571+
572+ h.Spin ()
573+ }
574+ ```
575+
576+ ** hertz versions 0.7.0 to 0.10.2** <br >
461577
462578``` go
463579package main
0 commit comments