-2

Long time listener, first time caller!

I'm a beginner with Go, but have several years of Python experience. So, please forgive my ignorance.

So, I am trying to parse a multi-level json response from a web server into map[string]interface{} type.

Example:

func GetResponse() (statusCode int, responseData map[string]interface{}){
    host := "https://somebogusurl.com/fake/json/data"
    
    request, err := http.NewRequest("GET", host, nil)
    if err != nil {
        panic(err)
    }

    client := http.Client{}
    response, err := client.Do(request)
    if err != nil {
        panic(err)
    }
    
    defer response.Body.Close()
    data, _ := ioutil.ReadAll(response.Body)
    json.Unmarshal([]byte(data), &responseData)
    return response.StatusCode, responseData
}

func main() {
    statusCode, data := GetResponse()
    fmt.Println(data["foo"].(map[string]interface{})["bar"])
}

As you can see, I am trying to access the nested values in this new map that is returned. However, I get the following error:

panic: interface conversion: interface {} is []interface {}, not map[string]interface {}

I believe I am trying to access nested data which is in an interface, not a map[string]interface based on the error. Any idea how I access nested data?

  • 2
    Does this answer your question? [golang how to access interface fields](https://stackoverflow.com/questions/21796151/golang-how-to-access-interface-fields) – 9214 Mar 25 '21 at 19:29

2 Answers2

1

The problem is that your object may be something like this:

{
    "x":[1,2,3]
}

And when json.Unmarshal is called, it will return a map similar to this one:

map[string]interface {}{"x":[]interface {}{1, 2, 3}}

When the json key contains an array it is transformed into a []interface{} as arrays can contain any kind of values

To get a map like the one you require, your object should have a shape similar to:

{
    "x":{
        "y":"z"
    }
}

After unmarshalling it you will get something like

map[string]interface {}{"x":map[string]interface {}{"y":"z"}}

If you don't know beforehand the kind of data that will come inside your object, you will have to use reflection to inspect values and avoid wrong type assertions or incorrect behavior. Another possibility is to check the second value returned by a type assertion or use a type switch. For example:

//With type assertion
if val,ok:=m["key"].(map[string]interface{});ok{
    //val is map[string]interface{} do something with inner dict
    val["subkey"]
}

//With type switch
switch val := m["key"].(type) {
    case []interface{}:
        //access values by index
        val[0]...
    case map[string]interface{}:
        //do something with inner dict
        val["subkey"]...
    }
}
Pablo Flores
  • 1,350
  • 13
  • 15
0

you can user struct replace map[string]interface{} .

Suppose you have the following JSON

 {
    "id": -26798974.698663697,
    "name": "et anim in consectetur",
    "department_id": 1113574.4678084403,
    "department_name": "aut",
    "department_path": "in",
    "ctime": "tempor culpa",
    "utime": "culpa ipsum officia d",
    "project_type": -63043086.205600575,
    "project_type_label": "",
    "manager_name": "aliquip incididunt",
    "manager_id": 33403365.665011227,
    "members": [
      {
        "id": -71868040.04283473,
        "name": "ullamco",
        "username": "dolor sed enim velit",
        "phone": "in",
        "email": "quis",
        "role": "et volu",
        "uemail": "in",
        "uphone": "id ut Duis"
      },
      {
        "id": -66953595.48747035,
        "name": "non velit",
        "username": "dolore irure elit reprehenderit",
        "phone": "in dolor voluptate enim",
        "email": "ipsum minim occaecat sunt",
        "role": "amet occaecat incididunt nisi",
        "uemail": "ea",
        "uphone": "adipisicing in sint"
      },
      {
        "id": 55743250.12837607,
        "name": "nisi dolore minim",
        "username": "sit Ut id proident deserunt",
        "phone": "dolore nulla",
        "email": "sunt id ex ea exercitation",
        "role": "reprehenderit commodo laborum enim consectetur",
        "uemail": "in nulla ullamco ea",
        "uphone": "eu"
      },
      {
        "id": -29129221.093446136,
        "name": "deserunt officia tempor Duis",
        "username": "cupidatat ut aute",
        "phone": "ex aute",
        "email": "in",
        "role": "mollit",
        "uemail": "minim",
        "uphone": "proident et qui nulla ullamco"
      }
    ]
  }

you can use the following struct to parse json

type Autogenerated struct {
    ID               float64 `json:"id"`
    Name             string  `json:"name"`
    DepartmentID     float64 `json:"department_id"`
    DepartmentName   string  `json:"department_name"`
    DepartmentPath   string  `json:"department_path"`
    Ctime            string  `json:"ctime"`
    Utime            string  `json:"utime"`
    ProjectType      float64 `json:"project_type"`
    ProjectTypeLabel string  `json:"project_type_label"`
    ManagerName      string  `json:"manager_name"`
    ManagerID        float64 `json:"manager_id"`
    Members          []struct {
        ID       float64 `json:"id"`
        Name     string  `json:"name"`
        Username string  `json:"username"`
        Phone    string  `json:"phone"`
        Email    string  `json:"email"`
        Role     string  `json:"role"`
        Uemail   string  `json:"uemail"`
        Uphone   string  `json:"uphone"`
    } `json:"members"`
}
yuan lin
  • 13
  • 2