mappath is a go library for traversing generic maps for values by keypath.
This package is most helpful when you need to pull out a view values from a deeply nested from some sort of map (typically from JSON). Instead of making numerous interim types, you can extract just the values at a known path.
This pairs well with something like mapstructure.
Standard go get
:
$ go get github.com/ryanfaerman/mappath
Consider a deeply nested JSON (much deeper than this example):
{
"hello": "world",
"goodbye": "moon",
"banana": [
{
"phone": "ring",
"ding": "ding"
}
]
}
where we need to extract the value at the path banana.0.phone
. With a
traditional approach, we'd need to create at least one interim struct or dig
through each level in our path with a combination of type-checking and
coercion.
if banana, ok := data["banana"]; ok {
if bananaVal, ok := banana.([]map[string]interface{}); ok {
if len(banana) >= 1 {
if item, ok := banana[0].(map[string]interface{}); ok {
// ... and so on ...
}
}
}
}
If there are multiple keypaths needing extraction, this gets old pretty quick.
Instead, we can read the JSON into a map[string]interface{}
and using Seek
,
this is almost trivial.
phone, err := Seek(".banana.0.phone", data)
if err != nil {
// handle appropriately
}
Granted, this will still need a type coercion (with a check) but we're only doing this once with far less error handling.
This also opens the door to reading that keypath from some other input, like a flag.
Recently, I've needed to extract only one or two fields from a deeply nested JSON structure. Each part I needed was at different keypaths. Instead of creating numerous throw-away structs, or coercing/type-checking each level, I figured I'd pull out this functionality.
Using something like mappath.Seek
with a single type-check, reduced the size
and complexity of my codebase. It also made it more readable, which is a Good
Thing.