Extract typed request data from url, body, header(s), and cookie(s)
into a map[string]any using a declarative field config. Supports nested
objects, slices, defaults, optional fields, and simple type conversion.
import "github.com/aatuh/pickmap"// Minimal URL decoder: first value per key.
type formDecoder struct{}
func (formDecoder) Decode(v url.Values) (map[string]any, error) {
m := make(map[string]any, len(v))
for k, vals := range v {
if len(vals) > 0 { m[k] = vals[0] }
}
return m, nil
}
// Optional conversions. Keys are semantic type names used in config.
conv := map[string]func(any) any{
"int64": func(x any) any {
switch t := x.(type) {
case string:
if n, err := strconv.ParseInt(t, 10, 64); err == nil { return n }
}
return nil
},
}
picker := pickmap.NewPickmap(formDecoder{}, conv)
cfg := &pickmap.MapFieldConfig{
Fields: map[string]*pickmap.MapFieldConfig{
"id": { Source: "url", ExpectedType: "int64" },
"name": { Source: "body" },
"token": { Source: "header", Optional: true },
},
}
m, err := picker.PickMap(r, cfg)
if err != nil { /* handle */ }
fmt.Printf("id=%v name=%v token=%v\n", m["id"], m["name"], m["token"])url,body,header/headers,cookie/cookies- Default source by method:
GET→url, others →body - A parent config
Sourcecascades to children unless a child sets its ownSource.
- If the raw body contains nested objects or arrays, define
Fieldsfor that key; nested maps are traversed accordingly. - If raw data is flat, composite keys like
parent.childare supported to pick nested pieces. - Slices of nested objects are supported; each element is processed.
ExpectedTypeconverts values. Built‑ins:int64,int,float64,bool. You can add more via theconversionMappassed to the picker.DefaultValueis applied when a value is missing.Optional: trueskips missing values instead of emitting empty ones.
- Body is decoded from JSON with
UseNumberto preserve numeric range; the request body is restored for downstream handlers. - Unknown
Sourcevalues cause a panic to surface misconfiguration.