Ramesh
Ramesh

Reputation: 35

Mapping JSON returned by REST API containing dynamic keys to a struct in Golang

I'm calling a REST API from my Go program which takes n number of hotel ids in the request and returns their data as a JSON. The response is like the following when say I pass 2 ids in the request, 1018089108070373346 and 2017089208070373346 :

{
 "data": {
  "1018089108070373346": {
    "name": "A Nice Hotel",
    "success": true
   },
  "2017089208070373346": {
    "name": "Another Nice Hotel",
    "success": true
   }
  }
}

Since I'm new to Golang I using a JSON Go tool available at http://mholt.github.io/json-to-go/ to get the struct representation for the above response. What I get is:

type Autogenerated struct {
    Data struct {
        Num1017089108070373346 struct {
            Name string `json:"name"`
            Success bool `json:"success"`
        } `json:"1017089108070373346"`
        Num2017089208070373346 struct {
            Name string `json:"name"`
            Success bool `json:"success"`
        } `json:"2017089208070373346"`
    } `json:"data"`
}

I cannot use the above struct because the actual id values and the number of ids I pass can be different each time, the JSON returned will have different keys. How can this situation be mapped to a struct ?

Thanks

Upvotes: 1

Views: 2154

Answers (2)

Mani
Mani

Reputation: 1635

Here is some sample code that utilizes Mellow Marmots answer and shows how to iterate over the items in the response.

test.json

{
 "data": {
  "1018089108070373346": {
    "name": "A Nice Hotel",
    "success": true
   },
  "2017089208070373346": {
    "name": "Another Nice Hotel",
    "success": true
   }
  }
}

test.go

package main

import (
    "encoding/json"
    "fmt"
    "os"
)

// Item struct
type Item struct {
    Name    string `json:"name"`
    Success bool   `json:"success"`
}

// Response struct
type Response struct {
    Data map[string]Item `json:"data"`
}

func main() {
    jsonFile, err := os.Open("test.json")
    if err != nil {
        fmt.Println("Error opening test file\n", err.Error())
        return
    }

    jsonParser := json.NewDecoder(jsonFile)
    var filedata Response
    if err = jsonParser.Decode(&filedata); err != nil {
        fmt.Println("Error while reading test file.\n", err.Error())
        return
    }

    for key, value := range filedata.Data {
        fmt.Println(key, value.Name, value.Success)
    }
}

Which outputs:

1018089108070373346 A Nice Hotel true
2017089208070373346 Another Nice Hotel true

Upvotes: 0

Thundercat
Thundercat

Reputation: 120951

Use a map:

type Item struct {
    Name string `json:"name"`
    Success bool `json:"success"`
} 
type Response struct {
    Data map[string]Item `json:"data"`
}

Run it on the playground

Upvotes: 3

Related Questions