1

I'm new to Golang and I recently wrote the following code snippet:

resp, _ := http.Get("https://api.vagalume.com.br/search.art?q=Aerosmith&limit=5")
obj := map[string]interface{}{}
responseData, _ := ioutil.ReadAll(resp.Body)
json.Unmarshal([]byte(string(responseData)), &obj)

The url: https://api.vagalume.com.br/search.art?q=Aerosmith&limit=5 should retrieve a nested JSON.

{
  "response":{
     "numFound":1,
     "start":0,
     "numFoundExact":true,
     "docs":[
      {
        "id":"b3ade68b3g6f86eda3",
        "url":"/aerosmith/",
        "band":"Aerosmith",
        "fmRadios":["...", "..."]
      }]
  },
  "highlighting":{
    "b3ade68b3g6f86eda3":{}}}

Wherease the line:

obj["response"]

is valid, but the line:

obj["response"]["docs"]

does not compile.

How can I access the content inside "response" -> "docs" ?

Edit: the answer Unmarshaling nested JSON objects is not good for me because I want to find a way to read a JSON object with unknown structure.

CrazySynthax
  • 13,662
  • 34
  • 99
  • 183

2 Answers2

3

You could do that this way for example:

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
)

type myData struct {
    Response struct {
        NumFound      int  `json:"numFound"`
        Start         int  `json:"start"`
        NumFoundExact bool `json:"numFoundExact"`
        Docs          []struct {
            ID       string   `json:"id"`
            URL      string   `json:"url"`
            Band     string   `json:"band"`
            FmRadios []string `json:"fmRadios"`
        } `json:"docs"`
    } `json:"response"`
    Highlighting struct {
        B3Ade68B3G6F86Eda3 struct {
        } `json:"b3ade68b3g6f86eda3"`
    } `json:"highlighting"`
}


func main() {
    resp, _ := http.Get("https://api.vagalume.com.br/search.art?q=Aerosmith&limit=5")
    responseData, _ := ioutil.ReadAll(resp.Body)
    d := myData{}
    err := json.Unmarshal(responseData, &d)
    if err != nil {
        panic(err)
    }
    fmt.Println(d.Response.Docs)
}

Output:

[{b3ade68b3g6f86eda3 /aerosmith/ Aerosmith [14634980201914128847|acustico 1464201608479108132|rock 1464720376206867533|rock-ballads 14647977281792658143|rock-classico 1470155219129532|romantico 1475867272151401|rock-das-raizes-ao-progressivo 1479752883943544|heavy-metal 1506975770142563|pop-rock 1508779923321353|para-viajar 1514919045178434|hits-anos-90 1521216096352408|hard-rock 1522179349368851|monday 1522261529679510|depre 1528233925925603|dia-dos-namorados 1534365009290224|favoritas-do-vagalume]}]

EDIT:

Or, as suggested, if you don't know the JSON's structure, you could use this:

package main

import (
    "github.com/tidwall/gjson"
    "io/ioutil"
    "net/http"
)


func main() {
    resp, _ := http.Get("https://api.vagalume.com.br/search.art?q=Aerosmith&limit=5")
    responseData, _ := ioutil.ReadAll(resp.Body)
    defer resp.Body.Close()

    value := gjson.GetBytes(responseData, "response.docs")
    println(value.String())
}

Output:

[
      {
        "id":"b3ade68b3g6f86eda3",
        "url":"/aerosmith/",
        "band":"Aerosmith",
        "fmRadios":["14634980201914128847|acustico",
          "1464201608479108132|rock",
          "1464720376206867533|rock-ballads",
          "14647977281792658143|rock-classico",
          "1470155219129532|romantico",
          "1475867272151401|rock-das-raizes-ao-progressivo",
          "1479752883943544|heavy-metal",
          "1506975770142563|pop-rock",
          "1508779923321353|para-viajar",
          "1514919045178434|hits-anos-90",
          "1521216096352408|hard-rock",
          "1522179349368851|monday",
          "1522261529679510|depre",
          "1528233925925603|dia-dos-namorados",
          "1534365009290224|favoritas-do-vagalume"]}]
baduker
  • 19,152
  • 9
  • 33
  • 56
3

If you don't want to (or can't) use a struct of a suitable type, you need a type-cast.

response, ok := obj["response"].(map[string]interface{})
if !ok {
    ... return an error
}
docs := response["docs"]

The type of obj is map[string]interface{}, so the type of any obj[<field>] is interface{}. If the value of that field is a JSON object, it will also be of type map[string]interface{} as defined in https://golang.org/pkg/encoding/json/#Unmarshal . You can see in that document the other types you may be interested in for the other fields.

Paul Hankin
  • 54,811
  • 11
  • 92
  • 118