github.com/cloudwego/hertz@v0.9.3/pkg/app/server/binding/config.go (about) 1 /* 2 * Copyright 2023 CloudWeGo Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package binding 18 19 import ( 20 stdJson "encoding/json" 21 "fmt" 22 "reflect" 23 "time" 24 25 exprValidator "github.com/bytedance/go-tagexpr/v2/validator" 26 inDecoder "github.com/cloudwego/hertz/pkg/app/server/binding/internal/decoder" 27 hJson "github.com/cloudwego/hertz/pkg/common/json" 28 "github.com/cloudwego/hertz/pkg/protocol" 29 "github.com/cloudwego/hertz/pkg/route/param" 30 ) 31 32 // BindConfig contains options for default bind behavior. 33 type BindConfig struct { 34 // LooseZeroMode if set to true, 35 // the empty string request parameter is bound to the zero value of parameter. 36 // NOTE: 37 // The default is false. 38 // Suitable for these parameter types: query/header/cookie/form . 39 LooseZeroMode bool 40 // DisableDefaultTag is used to add default tags to a field when it has no tag 41 // If is false, the field with no tag will be added default tags, for more automated binding. But there may be additional overhead. 42 // NOTE: 43 // The default is false. 44 DisableDefaultTag bool 45 // DisableStructFieldResolve is used to generate a separate decoder for a struct. 46 // If is false, the 'struct' field will get a single inDecoder.structTypeFieldTextDecoder, and use json.Unmarshal for decode it. 47 // It usually used to add json string to query parameter. 48 // NOTE: 49 // The default is false. 50 DisableStructFieldResolve bool 51 // EnableDecoderUseNumber is used to call the UseNumber method on the JSON 52 // Decoder instance. UseNumber causes the Decoder to unmarshal a number into an 53 // interface{} as a Number instead of as a float64. 54 // NOTE: 55 // The default is false. 56 // It is used for BindJSON(). 57 EnableDecoderUseNumber bool 58 // EnableDecoderDisallowUnknownFields is used to call the DisallowUnknownFields method 59 // on the JSON Decoder instance. DisallowUnknownFields causes the Decoder to 60 // return an error when the destination is a struct and the input contains object 61 // keys which do not match any non-ignored, exported fields in the destination. 62 // NOTE: 63 // The default is false. 64 // It is used for BindJSON(). 65 EnableDecoderDisallowUnknownFields bool 66 // TypeUnmarshalFuncs registers customized type unmarshaler. 67 // NOTE: 68 // time.Time is registered by default 69 TypeUnmarshalFuncs map[reflect.Type]inDecoder.CustomizeDecodeFunc 70 // Validator is used to validate for BindAndValidate() 71 Validator StructValidator 72 } 73 74 func NewBindConfig() *BindConfig { 75 return &BindConfig{ 76 LooseZeroMode: false, 77 DisableDefaultTag: false, 78 DisableStructFieldResolve: false, 79 EnableDecoderUseNumber: false, 80 EnableDecoderDisallowUnknownFields: false, 81 TypeUnmarshalFuncs: make(map[reflect.Type]inDecoder.CustomizeDecodeFunc), 82 Validator: defaultValidate, 83 } 84 } 85 86 // RegTypeUnmarshal registers customized type unmarshaler. 87 func (config *BindConfig) RegTypeUnmarshal(t reflect.Type, fn inDecoder.CustomizeDecodeFunc) error { 88 // check 89 switch t.Kind() { 90 case reflect.String, reflect.Bool, 91 reflect.Float32, reflect.Float64, 92 reflect.Int, reflect.Int64, reflect.Int32, reflect.Int16, reflect.Int8, 93 reflect.Uint, reflect.Uint64, reflect.Uint32, reflect.Uint16, reflect.Uint8: 94 return fmt.Errorf("registration type cannot be a basic type") 95 case reflect.Ptr: 96 return fmt.Errorf("registration type cannot be a pointer type") 97 } 98 if config.TypeUnmarshalFuncs == nil { 99 config.TypeUnmarshalFuncs = make(map[reflect.Type]inDecoder.CustomizeDecodeFunc) 100 } 101 config.TypeUnmarshalFuncs[t] = fn 102 return nil 103 } 104 105 // MustRegTypeUnmarshal registers customized type unmarshaler. It will panic if exist error. 106 func (config *BindConfig) MustRegTypeUnmarshal(t reflect.Type, fn func(req *protocol.Request, params param.Params, text string) (reflect.Value, error)) { 107 err := config.RegTypeUnmarshal(t, fn) 108 if err != nil { 109 panic(err) 110 } 111 } 112 113 func (config *BindConfig) initTypeUnmarshal() { 114 config.MustRegTypeUnmarshal(reflect.TypeOf(time.Time{}), func(req *protocol.Request, params param.Params, text string) (reflect.Value, error) { 115 if text == "" { 116 return reflect.ValueOf(time.Time{}), nil 117 } 118 t, err := time.Parse(time.RFC3339, text) 119 if err != nil { 120 return reflect.Value{}, err 121 } 122 return reflect.ValueOf(t), nil 123 }) 124 } 125 126 // UseThirdPartyJSONUnmarshaler uses third-party json library for binding 127 // NOTE: 128 // 129 // UseThirdPartyJSONUnmarshaler will remain in effect once it has been called. 130 func (config *BindConfig) UseThirdPartyJSONUnmarshaler(fn func(data []byte, v interface{}) error) { 131 hJson.Unmarshal = fn 132 } 133 134 // UseStdJSONUnmarshaler uses encoding/json as json library 135 // NOTE: 136 // 137 // The current version uses encoding/json by default. 138 // UseStdJSONUnmarshaler will remain in effect once it has been called. 139 func (config *BindConfig) UseStdJSONUnmarshaler() { 140 config.UseThirdPartyJSONUnmarshaler(stdJson.Unmarshal) 141 } 142 143 type ValidateErrFactory func(fieldSelector, msg string) error 144 145 type ValidateConfig struct { 146 ValidateTag string 147 ErrFactory ValidateErrFactory 148 } 149 150 func NewValidateConfig() *ValidateConfig { 151 return &ValidateConfig{} 152 } 153 154 // MustRegValidateFunc registers validator function expression. 155 // NOTE: 156 // 157 // If force=true, allow to cover the existed same funcName. 158 // MustRegValidateFunc will remain in effect once it has been called. 159 func (config *ValidateConfig) MustRegValidateFunc(funcName string, fn func(args ...interface{}) error, force ...bool) { 160 exprValidator.MustRegFunc(funcName, fn, force...) 161 } 162 163 // SetValidatorErrorFactory customizes the factory of validation error. 164 func (config *ValidateConfig) SetValidatorErrorFactory(errFactory ValidateErrFactory) { 165 config.ErrFactory = errFactory 166 } 167 168 // SetValidatorTag customizes the factory of validation error. 169 func (config *ValidateConfig) SetValidatorTag(tag string) { 170 config.ValidateTag = tag 171 }