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.
CodePudding user response:
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")
}