Palash Nigam
Palash Nigam

Reputation: 2012

Unmarshalling complex json in Go

So I am trying to fetch the analytics of an app by pinging and endpoint. I make the GET request which is successfull (no errors there) but I am unable to decode the JSON

I need to to decode the following json into structs

{
  "noResultSearches": {
    "results": [
      {
        "count": 1,
        "key": "\"note 9\""
      },
      {
        "count": 1,
        "key": "nokia"
      }
    ]
  },
  "popularSearches": {
    "results": [
      {
        "count": 4,
        "key": "6"
      },
      {
        "count": 2,
        "key": "\"note 9\""
      },
      {
        "count": 1,
        "key": "nokia"
      }
    ]
  },
  "searchVolume": {
    "results": [
      {
        "count": 7,
        "key": 1537401600000,
        "key_as_string": "2018/09/20 00:00:00"
      }
    ]
  }
}

For which I am using the following structs

type analyticsResults struct {
    Count int    `json:"count"`
    Key   string `json:"key"`
}

type analyticsVolumeResults struct {
    Count     int    `json:"count"`
    Key       int64 `json:"key"`
    DateAsStr string `json:"key_as_string"`
}

type analyticsPopularSearches struct {
    Results []analyticsResults `json:"results"`
}

type analyticsNoResultSearches struct {
    Results []analyticsResults `json:"results"`
}

type analyticsSearchVolume struct {
    Results []analyticsVolumeResults `json:"results"`
}

type overviewAnalyticsBody struct {
    NoResultSearches analyticsNoResultSearches `json:"noResultSearches"`
    PopularSearches  analyticsPopularSearches  `json:"popularSearches"`
    SearchVolume     analyticsSearchVolume     `json:"searchVolume"`
}

I make a GET request to an endpoint and then use the response body to decode the json but I get an error. Following is a part of the code that stays in my ShowAnalytics function

func ShowAppAnalytics(app string) error {
  spinner.StartText("Fetching app analytics")
  defer spinner.Stop()

  fmt.Println()
  req, err := http.NewRequest("GET", "<some-endpoint>", nil)
  if err != nil {
      return err
  }
  resp, err := session.SendRequest(req)
  if err != nil {
      return err
  }
  spinner.Stop()

  var res overviewAnalyticsBody
  dec := json.NewDecoder(resp.Body)
  err = dec.Decode(&res)
  if err != nil {
      return err
  }

  fmt.Println(res)

  return nil
}

json: cannot unmarshal array into Go struct field overviewAnalyticsBody.noResultSearches of type app.analyticsNoResultSearches

What am I doing wrong here? Why do I get this error?

Upvotes: 0

Views: 792

Answers (1)

icza
icza

Reputation: 417612

EDIT: After you edited, your current code works as-is. Check it out here: Go Playground.

Original answer follows.


There is some inconsistency between the code you posted and the error you get.

I tried it on the Go Playground (here's your version), and I get the following error:

json: cannot unmarshal number into Go struct field analyticsVolumeResults.key of type string

We get this error because in the JSON searchVolume.results.key is a number:

    "key": 1537401600000,

And you used string in the Go model:

Key       string `json:"key"`

If we change it to int64:

Key       int64 `json:"key"`

It works, and prints (try it on the Go Playground):

{{[{1 "note 9"} {1 nokia}]} {[{4 6} {2 "note 9"} {1 nokia}]} {[{7 1537401600000 2018/09/20 00:00:00}]}}

If that key may sometimes be a number and sometimes a string, you may also use json.Number in the Go model:

Key       json.Number `json:"key"`

Upvotes: 1

Related Questions