Norio Akagi Norio Akagi - 1 year ago 66
JSON Question

What is the best way to handle "a single element or an array" JSON property in Go?

Now we have a JSON HTTP request data which would be a single element like

{"data": {"id":1}}
OR an array of elements like
{"data": [{"id":1}, {"id":2}]}

Since a client side cannot change the implementation, we have to keep and accept this data structure.

Currently I implement struct like:

type Request struct {
rawData json.RawMessage `json:"data"`

Data *Data `json:"-"`
DataList []*Data `json:"-"`

And first parse "data" property as json.RawMessage into variable
, try parsing as a single element first, then if it fails try parsing as an array.

if err := json.Unmarshal(req.rawData, &req.Data); err != nil {
if err := json.Unmarshal(req.RawData, &req.DataList); err != nil {
return errors.New("could not parse data")
} else if len(req.DataList) < 1 {
return errors.New("empty list")

In this case, later when we want to use this data, we can check if
is a single element or an array by
len(req.Datalist) >= 1
. (Or I can set some flag to show that like
in the struct, when parsing).

Is there any idiomatic way to achieve the same result in Go other than what I'm doing?

Answer Source

Here's how I would do it:

type Request struct {
   RawData json.RawMessage `json:"data"  // export field for unmarshal of entire request
   DataList []*Data `json:"-"`           // always use slice

// Is it an array?
if bytes.HasPrefix(bytes.TrimSpace(req.RawData), []byte{'['})) {
   if err := json.Unmarshal(req.RawData, &req.DataList); err != nil {
       // handle error parsing array
} else {
   var v Data
   if err := json.Unmarshal(req.RawData, &v); err != nil {
       // handle error parsing single value
   req.DataList = []*Data{&v)
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download