Maxim Samburskiy Maxim Samburskiy - 1 year ago 103
JSON Question

Decode both map and array json

External API returns empty array if no items:


...or map with items:

{"items":{"1": {...}, "2": {...}}}

How can I decode both of them? I tried using this struct:

var response struct {
Items map[string]Item
Array []Item `json:"items"`

But it doesn't work.

UPDATE: Best if both (array and object) will produce a
(empty and filled)

Answer Source

If you need to unmarshall to a variable type, the easiest way is to unmarshal into a map[string]interface{} and type-assert (or in this case, type-switch) your way out.

func Unmarshal(data []byte) (map[string]Item, error) {
    var d struct {
        Items interface{} `json:"items"`
    if err := json.Unmarshal(data, &d); err != nil {
        return nil, err
    switch dv := d.Items.(type) {
    case []interface{}:
        if len(dv) == 0 {
            return nil, nil
    case map[string]interface{}:
        m := make(map[string]Item)
        for k, v := range dv {
            m[k] = Item(v)
        return m, nil
    // fallthrough return if different type, or non-empty array
    // Could have put this in a default case, but this catches non-empty arrays too
    return nil, fmt.Errorf("unexpected type in json")

Here's an example showing it works for both of your provided examples:

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download