github.com/johnnyeven/libtools@v0.0.0-20191126065708-61829c1adf46/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/johnnyeven/libtools/courier/status_error" 11 "github.com/johnnyeven/libtools/reflectx" 12 "github.com/johnnyeven/libtools/strutil" 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 func (p *ParameterMeta) Validate() (bool, status_error.ErrorFields) { 134 errMsgMap := ErrMsgMap{} 135 parentField := "" 136 137 if reflectx.IndirectType(p.Field.Type).Kind() == reflect.Struct { 138 validateScan := NewScanner() 139 isValid, errMsgs := validateScan.Validate(p.Value, p.Field.Type) 140 if !isValid { 141 errMsgMap = errMsgMap.Merge(errMsgs) 142 } 143 if p.In == "formData" { 144 parentField = p.Name 145 } 146 } else { 147 errMsg := MarshalAndValidate( 148 p.Value, p.Field.Type, 149 p.DefaultValue, p.Required, 150 p.TagValidate, p.TagErrMsg, 151 ) 152 153 if errMsg != "" { 154 errMsgMap[p.Name] = errMsg 155 } 156 } 157 158 return len(errMsgMap) == 0, errMsgMap.ErrorFieldsIn(p.In, parentField) 159 } 160 161 func BytesList(ss ...string) (dataList [][]byte) { 162 for _, s := range ss { 163 dataList = append(dataList, []byte(s)) 164 } 165 return 166 } 167 168 func ContentMarshal(rv reflect.Value, in string, format string) (dataList [][]byte, err error) { 169 if rv.Kind() == reflect.Ptr && rv.IsNil() { 170 return 171 } 172 173 rv = reflect.Indirect(rv) 174 175 if marshal, ok := rv.Interface().(encoding.TextMarshaler); ok { 176 data, marshalErr := marshal.MarshalText() 177 if marshalErr != nil { 178 err = marshalErr 179 return 180 } 181 dataList = [][]byte{data} 182 return 183 } 184 185 switch rv.Kind() { 186 case reflect.Map, reflect.Struct: 187 data, errForMarshal := GetContentTransformer(format).Marshal(rv.Interface()) 188 if errForMarshal != nil { 189 err = errForMarshal 190 return 191 } 192 dataList = [][]byte{data} 193 return 194 case reflect.Slice, reflect.Array: 195 if data, ok := rv.Interface().([]byte); ok { 196 dataList = [][]byte{data} 197 return 198 } 199 if in == "body" { 200 data, errForMarshal := GetContentTransformer(format).Marshal(rv.Interface()) 201 if errForMarshal != nil { 202 err = errForMarshal 203 return 204 } 205 dataList = [][]byte{data} 206 return 207 } 208 for i := 0; i < rv.Len(); i++ { 209 itemsList, errForStringify := ContentMarshal(rv.Index(i), in, format) 210 if errForStringify != nil { 211 err = errForStringify 212 return 213 } 214 dataList = append(dataList, itemsList...) 215 } 216 return 217 default: 218 data, errForStringify := Stringify(rv.Interface()) 219 for errForStringify != nil { 220 err = errForStringify 221 } 222 dataList = [][]byte{data} 223 return 224 } 225 } 226 227 func ContentUnmarshal(rv reflect.Value, tpe reflect.Type, in string, name string, format string, dataList ...[]byte) error { 228 if len(dataList) == 0 || len(dataList[0]) == 0 { 229 return nil 230 } 231 232 if rv.Kind() == reflect.Ptr && rv.IsNil() && rv.CanSet() { 233 rv.Set(reflect.New(reflectx.IndirectType(tpe))) 234 } 235 236 rv = reflect.Indirect(rv) 237 238 if textUnmarshaler, ok := rv.Addr().Interface().(encoding.TextUnmarshaler); ok { 239 if err := textUnmarshaler.UnmarshalText(dataList[0]); err != nil { 240 return err 241 } 242 return nil 243 } 244 245 switch rv.Kind() { 246 case reflect.Map, reflect.Struct: 247 if rv.CanAddr() { 248 rv = rv.Addr() 249 } 250 return structUnmarshal(in, name, format, dataList[0], rv.Interface()) 251 case reflect.Slice: 252 if _, ok := rv.Interface().([]byte); ok { 253 rv.SetBytes(dataList[0]) 254 return nil 255 } 256 257 if in == "body" { 258 if rv.CanAddr() { 259 rv = rv.Addr() 260 } 261 return structUnmarshal(in, name, format, dataList[0], rv.Interface()) 262 } 263 264 sliceRv := reflect.MakeSlice(tpe, len(dataList), cap(dataList)) 265 266 itemType := rv.Type().Elem() 267 for i, data := range dataList { 268 err := ContentUnmarshal(sliceRv.Index(i), itemType, in, name, format, data) 269 if err != nil { 270 return err 271 } 272 } 273 274 rv.Set(sliceRv) 275 276 return nil 277 case reflect.Array: 278 if in == "body" { 279 if rv.CanAddr() { 280 rv = rv.Addr() 281 } 282 return structUnmarshal(in, name, format, dataList[0], rv.Interface()) 283 } 284 itemType := rv.Type().Elem() 285 for i, data := range dataList { 286 err := ContentUnmarshal(rv.Index(i), itemType, in, name, format, data) 287 if err != nil { 288 return err 289 } 290 } 291 return nil 292 default: 293 return strutil.ConvertFromStr(string(dataList[0]), rv) 294 } 295 } 296 297 func structUnmarshal(in string, rootField string, format string, data []byte, v interface{}) error { 298 err := GetContentTransformer(format).Unmarshal(data, v) 299 if err != nil { 300 statusError := status_error.InvalidBodyStruct.StatusError() 301 if unmarshalTypeErr, ok := err.(*json.UnmarshalTypeError); ok { 302 return statusError.WithErrorField(in, LocateJSONPath(data, unmarshalTypeErr.Offset), unmarshalTypeErr.Error()) 303 } 304 return statusError.WithErrorField(in, rootField, "参数格式错误").WithDesc(err.Error()) 305 } 306 return nil 307 }