Convert an object to an array of objects (JSON) in Go

Issue

I am converting a JS API to Go. I use data from a third party where sometimes a property is an object of various key, value rather than an array of objects (of key, value).

So in my frontend if it’s an object it won’t render so I convert it into an array of objects.

Currently in JS I’m doing this:

if (!Array.isArray(data.attributes)) {
      // convert into array of objects; only works for non separate key:key value:value
      data.attributes = Object.entries(data.attributes).map(
        ([key, value]) => ({
          type: key,
          value: value,
        })
      );
    }

data is a property in a JSON response like:
{... data: { "attributes": [{...}{...}]}

So occasionally attributes will be {... data: { "attributes": {name: "John", age: "20" }:

How would I do something like this in Go? Thanks.

Solution

With a declared type you can implement the json.Unmarshaler interface to customize how the JSON will be unmarshaled.

In the implementation you can check whether or not the JSON data represents an Object or an Array by simply looking at the first and last byte to see if its {-and-} or [-and-]. Based on that check you can then decide how to proceed further, here’s an example:

type Attr struct {
    Type  string
    Value interface{}
}

type AttrList []Attr

func (ls *AttrList) UnmarshalJSON(data []byte) error {
    if len(data) == 0 { // nothing to do
        return nil
    }

    switch last := len(data)-1; {
    // is array?
    case data[0] == '[' && data[last] == ']':
        return json.Unmarshal(data, (*[]Attr)(ls))

    // is object?
    case data[0] == '{' && data[last] == '}':
        var obj map[string]interface{}
        if err := json.Unmarshal(data, &obj); err != nil {
            return err
        }
        for key, value := range obj {
            *ls = append(*ls, Attr{Type: key, Value: value})
        }
        return nil
    }

    return errors.New("unsupported JSON type for AttrList")
}

https://go.dev/play/p/X5LV8G87bLJ

Answered By – mkopriva

Answer Checked By – Terry (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.