github.com/profzone/eden-framework@v1.0.10/pkg/courier/transport_http/transform/parameter_meta.go (about) 1 package transform 2 3 import ( 4 "encoding" 5 "encoding/json" 6 "io" 7 "io/ioutil" 8 "reflect" 9 10 "github.com/profzone/eden-framework/pkg/courier/status_error" 11 "github.com/profzone/eden-framework/pkg/reflectx" 12 "github.com/profzone/eden-framework/pkg/strings" 13 ) 14 15 func NewParameterMeta(field *reflect.StructField, rv reflect.Value, tagIn string, tagInFlags TagFlags) *ParameterMeta { 16 name, nameFlags := GetParameterDisplayName(field) 17 18 p := &ParameterMeta{ 19 Name: name, 20 In: tagIn, 21 InFlags: tagInFlags, 22 Field: field, 23 Value: rv, 24 } 25 26 style, _, styleFlags := GetTagStyle(field) 27 p.Style = style 28 p.StyleFlags = styleFlags 29 30 if p.Style == "" { 31 switch p.In { 32 case "query", "cookie": 33 p.Style = "form" 34 // todo set explode as default 35 case "path", "header": 36 p.Style = "simple" 37 } 38 } 39 40 p.Format, _, _ = GetTagFmt(field) 41 if p.Format == "" { 42 p.Format = "json" 43 } 44 45 defaultValue, hasDefaultTag := GetTagDefault(field) 46 p.DefaultValue = defaultValue 47 48 p.Required = true 49 if hasOmitempty, ok := nameFlags["omitempty"]; ok { 50 p.Required = !hasOmitempty 51 } else { 52 // todo don't use non-default as required 53 p.Required = !hasDefaultTag 54 } 55 56 tagValidate, _ := GetTagValidate(field) 57 p.TagValidate = tagValidate 58 59 tagErrMsg, _ := GetTagErrMsg(field) 60 p.TagErrMsg = tagErrMsg 61 62 return p 63 } 64 65 type ParameterMeta struct { 66 Name string 67 In string 68 Format string 69 70 InFlags TagFlags 71 Field *reflect.StructField 72 Value reflect.Value 73 74 Style string 75 StyleFlags TagFlags 76 77 DefaultValue string 78 Required bool 79 80 TagValidate string 81 TagErrMsg string 82 } 83 84 func (p *ParameterMeta) IsExplode() bool { 85 return p.StyleFlags != nil && p.StyleFlags["explode"] 86 } 87 88 func (p *ParameterMeta) IsMultipart() bool { 89 return p.InFlags != nil && p.InFlags["multipart"] 90 } 91 92 // for parameter 93 func (p *ParameterMeta) UnmarshalStringAndValidate(ss ...string) error { 94 return p.UnmarshalAndValidate(BytesList(ResolveCommaSplitValues(p.Field.Type, ss...)...)...) 95 } 96 97 func (p *ParameterMeta) UnmarshalAndValidate(dataList ...[]byte) error { 98 if err := p.Unmarshal(dataList...); err != nil { 99 if statusErr, ok := err.(*status_error.StatusError); ok { 100 return statusErr 101 } 102 return status_error.InvalidField.StatusError().WithErrorField(p.In, p.Name, err.Error()) 103 } 104 if valid, errFields := p.Validate(); !valid { 105 return status_error.InvalidField.StatusError().WithErrorFields(errFields...) 106 } 107 return nil 108 } 109 110 // for body 111 func (p *ParameterMeta) UnmarshalFromReader(reader io.Reader) error { 112 if reader == nil { 113 return status_error.ReadFailed.StatusError() 114 } 115 data, readErr := ioutil.ReadAll(reader) 116 if readErr != nil { 117 return status_error.ReadFailed.StatusError() 118 } 119 if len(data) == 0 { 120 return status_error.InvalidBodyStruct.StatusError().WithDesc("empty body") 121 } 122 return p.UnmarshalAndValidate(data) 123 } 124 125 func (p *ParameterMeta) Unmarshal(datalist ...[]byte) error { 126 return ContentUnmarshal(p.Value, p.Field.Type, p.In, p.Name, p.Format, datalist...) 127 } 128 129 func (p *ParameterMeta) Marshal() (dataList [][]byte, err error) { 130 return ContentMarshal(p.Value, p.In, p.Format) 131 } 132 133 var rtypeEncodingTextMarshaler = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() 134 135 func (p *ParameterMeta) Validate() (bool, status_error.ErrorFields) { 136 errMsgMap := ErrMsgMap{} 137 parentField := "" 138 139 typ := reflectx.IndirectType(p.Field.Type) 140 141 kind := typ.Kind() 142 if (kind == reflect.Struct || kind == reflect.Slice || kind == reflect.Array) && !typ.Implements(rtypeEncodingTextMarshaler) { 143 validateScan := NewScanner() 144 isValid, errMsgs := validateScan.Validate(p.Value, p.Field.Type) 145 if !isValid { 146 errMsgMap = errMsgMap.Merge(errMsgs) 147 } 148 if p.In == "formData" { 149 parentField = p.Name 150 } 151 } else { 152 errMsg := MarshalAndValidate( 153 p.Value, p.Field.Type, 154 p.DefaultValue, p.Required, 155 p.TagValidate, p.TagErrMsg, 156 ) 157 158 if errMsg != "" { 159 errMsgMap[p.Name] = errMsg 160 } 161 } 162 163 return len(errMsgMap) == 0, errMsgMap.ErrorFieldsIn(p.In, parentField) 164 } 165 166 func BytesList(ss ...string) (dataList [][]byte) { 167 for _, s := range ss { 168 dataList = append(dataList, []byte(s)) 169 } 170 return 171 } 172 173 func ContentMarshal(rv reflect.Value, in string, format string) (dataList [][]byte, err error) { 174 if rv.Kind() == reflect.Ptr && rv.IsNil() { 175 return 176 } 177 178 rv = reflect.Indirect(rv) 179 180 if marshal, ok := rv.Interface().(encoding.TextMarshaler); ok { 181 data, marshalErr := marshal.MarshalText() 182 if marshalErr != nil { 183 err = marshalErr 184 return 185 } 186 dataList = [][]byte{data} 187 return 188 } 189 190 switch rv.Kind() { 191 case reflect.Map, reflect.Struct: 192 data, errForMarshal := GetContentTransformer(format).Marshal(rv.Interface()) 193 if errForMarshal != nil { 194 err = errForMarshal 195 return 196 } 197 dataList = [][]byte{data} 198 return 199 case reflect.Slice, reflect.Array: 200 if data, ok := rv.Interface().([]byte); ok { 201 dataList = [][]byte{data} 202 return 203 } 204 if in == "body" { 205 data, errForMarshal := GetContentTransformer(format).Marshal(rv.Interface()) 206 if errForMarshal != nil { 207 err = errForMarshal 208 return 209 } 210 dataList = [][]byte{data} 211 return 212 } 213 for i := 0; i < rv.Len(); i++ { 214 itemsList, errForStringify := ContentMarshal(rv.Index(i), in, format) 215 if errForStringify != nil { 216 err = errForStringify 217 return 218 } 219 dataList = append(dataList, itemsList...) 220 } 221 return 222 default: 223 data, errForStringify := Stringify(rv.Interface()) 224 if errForStringify != nil { 225 err = errForStringify 226 return 227 } 228 dataList = [][]byte{data} 229 return 230 } 231 } 232 233 func ContentUnmarshal(rv reflect.Value, tpe reflect.Type, in string, name string, format string, dataList ...[]byte) error { 234 if len(dataList) == 0 || len(dataList[0]) == 0 { 235 return nil 236 } 237 238 if rv.Kind() == reflect.Ptr && rv.IsNil() && rv.CanSet() { 239 rv.Set(reflect.New(reflectx.IndirectType(tpe))) 240 } 241 242 rv = reflect.Indirect(rv) 243 244 if textUnmarshaler, ok := rv.Addr().Interface().(encoding.TextUnmarshaler); ok { 245 if err := textUnmarshaler.UnmarshalText(dataList[0]); err != nil { 246 return err 247 } 248 return nil 249 } 250 251 switch rv.Kind() { 252 case reflect.Map, reflect.Struct: 253 if rv.CanAddr() { 254 rv = rv.Addr() 255 } 256 return structUnmarshal(in, name, format, dataList[0], rv.Interface()) 257 case reflect.Slice: 258 if _, ok := rv.Interface().([]byte); ok { 259 rv.SetBytes(dataList[0]) 260 return nil 261 } 262 263 if in == "body" { 264 if rv.CanAddr() { 265 rv = rv.Addr() 266 } 267 return structUnmarshal(in, name, format, dataList[0], rv.Interface()) 268 } 269 270 sliceRv := reflect.MakeSlice(tpe, len(dataList), cap(dataList)) 271 272 itemType := rv.Type().Elem() 273 for i, data := range dataList { 274 err := ContentUnmarshal(sliceRv.Index(i), itemType, in, name, format, data) 275 if err != nil { 276 return err 277 } 278 } 279 280 rv.Set(sliceRv) 281 282 return nil 283 case reflect.Array: 284 if in == "body" { 285 if rv.CanAddr() { 286 rv = rv.Addr() 287 } 288 return structUnmarshal(in, name, format, dataList[0], rv.Interface()) 289 } 290 itemType := rv.Type().Elem() 291 for i, data := range dataList { 292 err := ContentUnmarshal(rv.Index(i), itemType, in, name, format, data) 293 if err != nil { 294 return err 295 } 296 } 297 return nil 298 default: 299 return str.ConvertFromStr(string(dataList[0]), rv) 300 } 301 } 302 303 func structUnmarshal(in string, rootField string, format string, data []byte, v interface{}) error { 304 err := GetContentTransformer(format).Unmarshal(data, v) 305 if err != nil { 306 statusError := status_error.InvalidBodyStruct.StatusError() 307 if unmarshalTypeErr, ok := err.(*json.UnmarshalTypeError); ok { 308 if unmarshalTypeErr.Type == nil { 309 return statusError.WithErrorField(in, LocateJSONPath(data, unmarshalTypeErr.Offset), unmarshalTypeErr.Value) 310 } 311 return statusError.WithErrorField(in, LocateJSONPath(data, unmarshalTypeErr.Offset), unmarshalTypeErr.Error()) 312 } 313 return statusError.WithErrorField(in, rootField, "参数格式错误").WithDesc(err.Error()) 314 } 315 return nil 316 }