mapstructure is a Go library for decoding generic map values to structures and vice versa, while providing helpful error handling.
This library is most useful when decoding values from some data stream (JSON, Gob, etc.) where you don’t quite know the structure of the underlying data until you read a part of it. You can therefore read a map[string]interface{} and use this library to decode it into the proper underlying native Go structure.
Go offers fantastic standard libraries for decoding formats such as JSON. The standard method is to have a struct pre-created, and populate that struct from the bytes of the encoded format. This is great, but the problem is if you have configuration or an encoding that changes slightly depending on specific fields. For example, consider this JSON:
1 2 3 4
{ "type": "person", "name": "Mitchell" }
Perhaps we can’t populate a specific structure without first reading the “type” field from the JSON. We could always do two passes over the decoding of the JSON (reading the “type” first, and the rest later). However, it is much simpler to just decode this into a map[string]interface{} structure, read the “type” key, then use something like this library to decode it into the proper structure.
type Person struct { Name string Age int Emails []string Extra map[string]string }
// This input can come from anywhere, but typically comes from // something like decoding JSON where we're not quite sure of the // struct initially. input := map[string]interface{}{ "name": "Mitchell", "age": 91, "emails": []string{"one", "two", "three"}, "extra": map[string]string{ "twitter": "mitchellh", }, }
var result Person err := Decode(input, &result) if err != nil { panic(err) }
// Squashing multiple embedded structs is allowed using the squash tag. // This is demonstrated by creating a composite struct of multiple types // and decoding into it. In this case, a person can carry with it both // a Family and a Location, as well as their own FirstName. type Family struct { LastName string } type Location struct { City string } type Person struct { Family `mapstructure:",squash"` Location `mapstructure:",squash"` FirstName string }
// This input can come from anywhere, but typically comes from // something like decoding JSON where we're not quite sure of the // struct initially. input := map[string]interface{}{ "name": "Mitchell", "age": 91, "email": "[email protected]", }
// For metadata, we make a more advanced DecoderConfig so we can // more finely configure the decoder that is used. In this case, we // just tell the decoder we want to track metadata. var md Metadata var result Person config := &DecoderConfig{ Metadata: &md, Result: &result, }
// Add omitempty annotation to avoid map keys for empty values type Family struct { LastName string } type Location struct { City string } type Person struct { *Family `mapstructure:",omitempty"` *Location `mapstructure:",omitempty"` Age int FirstName string }
result := &map[string]interface{}{} input := Person{FirstName: "Somebody"} err := Decode(input, &result) if err != nil { panic(err) }
// Note that the mapstructure tags defined in the struct type // can indicate which fields the values are mapped to. type Person struct { Name string Age int Other map[string]interface{} `mapstructure:",remain"` }
// Note that the mapstructure tags defined in the struct type // can indicate which fields the values are mapped to. type Person struct { Name string`mapstructure:"person_name"` Age int`mapstructure:"person_age"` }
type Person struct { Name string Age int Emails []string }
// This input can come from anywhere, but typically comes from // something like decoding JSON, generated by a weakly typed language // such as PHP. input := map[string]interface{}{ "name": 123, // number => string "age": "42", // string => number "emails": map[string]interface{}{}, // empty map => empty array }
var result Person config := &DecoderConfig{ WeaklyTypedInput: true, Result: &result, }