MCPcopy
hub / github.com/labstack/echo / bindData

Function bindData

bind.go:208–359  ·  view source on GitHub ↗

bindData will bind data ONLY fields in destination struct that have EXPLICIT tag

(destination any, data map[string][]string, tag string, dataFiles map[string][]*multipart.FileHeader)

Source from the content-addressed store, hash-verified

206
207// bindData will bind data ONLY fields in destination struct that have EXPLICIT tag
208func bindData(destination any, data map[string][]string, tag string, dataFiles map[string][]*multipart.FileHeader) error {
209 if destination == nil || (len(data) == 0 && len(dataFiles) == 0) {
210 return nil
211 }
212 hasFiles := len(dataFiles) > 0
213 typ := reflect.TypeOf(destination).Elem()
214 val := reflect.ValueOf(destination).Elem()
215
216 // Support binding to limited Map destinations:
217 // - map[string][]string,
218 // - map[string]string <-- (binds first value from data slice)
219 // - map[string]any
220 // You are better off binding to struct but there are user who want this map feature. Source of data for these cases are:
221 // params,query,header,form as these sources produce string values, most of the time slice of strings, actually.
222 if typ.Kind() == reflect.Map && typ.Key().Kind() == reflect.String {
223 k := typ.Elem().Kind()
224 isElemInterface := k == reflect.Interface
225 isElemString := k == reflect.String
226 isElemSliceOfStrings := k == reflect.Slice && typ.Elem().Elem().Kind() == reflect.String
227 if !isElemSliceOfStrings && !isElemString && !isElemInterface {
228 return nil
229 }
230 if val.IsNil() {
231 val.Set(reflect.MakeMap(typ))
232 }
233 for k, v := range data {
234 if isElemString {
235 val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v[0]))
236 } else if isElemInterface {
237 // To maintain backward compatibility, we always bind to the first string value
238 // and not the slice of strings when dealing with map[string]any{}
239 val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v[0]))
240 } else {
241 val.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v))
242 }
243 }
244 return nil
245 }
246
247 // !struct
248 if typ.Kind() != reflect.Struct {
249 if tag == "param" || tag == "query" || tag == "header" {
250 // incompatible type, data is probably to be found in the body
251 return nil
252 }
253 return errors.New("binding element must be a struct")
254 }
255
256 meta := bindMetaFor(typ)
257 for fi := range meta.fields { // iterate over all destination fields
258 fm := &meta.fields[fi]
259 structField := val.Field(fm.index)
260 if fm.anonymous {
261 if structField.Kind() == reflect.Pointer {
262 structField = structField.Elem()
263 }
264 }
265 if !structField.CanSet() {

Callers 7

BindPathValuesFunction · 0.85
BindQueryParamsFunction · 0.85
BindBodyFunction · 0.85
BindHeadersFunction · 0.85
TestBindbindDataFunction · 0.85

Calls 8

bindMetaForFunction · 0.85
isFieldMultipartFileFunction · 0.85
unmarshalInputsToFieldFunction · 0.85
unmarshalInputToFieldFunction · 0.85
setWithProperTypeFunction · 0.85
SetMethod · 0.80
tagNameMethod · 0.80

Tested by 3

TestBindbindDataFunction · 0.68

Used in the wild real call sites across dependent graphs

searching dependent graphs…