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.

3
  • No. because I don't know that structure of the JSON. Commented Oct 3, 2020 at 16:56
  • 2
    If you don't know how the JSON is going to look like, you might want to use a library that parses json for you. eg: github.com/tidwall/gjson. You can call it as gjson.Get(json_string, "response.docs") Commented Oct 3, 2020 at 16:58
  • @pikaynu Thanks. tidwall/gjson is the answer. Commented Oct 3, 2020 at 17:17

2 Answers 2

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"]}]
Sign up to request clarification or add additional context in comments.

Comments

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.