golang: Encode/Decode arbitrary JSON

Just a quick post in case I forget how to do this in future. I had a use case for working with reading arbitrary JSON from a file and parsing it using Golang, which meant that the recommended way of using structs wasn’t suitable.

json.Marshal

The first thing to do was marshal a custom data structure into being a JSON string using json.Marshal. This was fairly straightforward to do:

cacheContent := map[string]interface{}{
        "foo": "bar",
        "baz": map[string]interface{}{
            "bee": "boo",
        },
    }

    str, err := json.Marshal(cacheContent)
    if err != nil {
        fmt.Println("Error encoding JSON")
        return
    }

    fmt.Println(string(str))
    # => {"baz":{"bee":"boo"},"foo":"bar"}

json.Unmarshal

json.Unmarshal was the tough one to work out. As it turns out, all you need to do is define a map of string => interface and then unmarshal into this structure. Go will take care of the rest.

# Using the "str" variable that we created using json.Marshal earlier
var x map[string]interface{}
json.Unmarshal([]byte(str), &x)
fmt.Println("%v", x)
# => %v map[baz:map[bee:boo] foo:bar]

# Using some hand crafted JSON. This could come from a file, web service, anything
str2 := "{"foo":{"baz": [1,2,3]}}"

var y map[string]interface{}
json.Unmarshal([]byte(str2), &y)

fmt.Println("%v", y)
# => %v map[foo:map[baz:[1 2 3]]]

Once the data is un-marshalled, you can access it as follows:

fmt.Printf("%v", y["foo"].(map[string]interface{})["baz"])
# => [1,2,3]

As we’re un-marshalling into an interface, we need to inform go what data type each key is before we can perform operations on it. This is what the .(map[string]interface{}) does


Published:
August 04, 2014

Category
How To