Trying to understand json.unmarshal

Hi,

Could not be more new to Go - but loving it!

I want to establish a repeatable chunk of code for GETting a chunk of json from an elasticsearch node and processing it. Here is what I have so far (please don’t laugh!):

package main 

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

type Elastic struct {
	Status string `json:"status"`
	Name string `json:"name"`
}

func main() {

	// Set up the URL
	url := "http://localhost:9200"

	// Execute GET then close the body
	response, err := http.Get(url)
	if err != nil { log.Fatal(err) }
	defer response.Body.Close()

	// Echo the current type of the body object
	i := reflect.TypeOf(response)
	fmt.Println("\nReponse is: ", i)

	// Convert the body to uint8
	responseData, err := ioutil.ReadAll(response.Body)
	if err != nil { log.Fatal(err) }
	i = reflect.TypeOf(responseData)

	// Echo the current type of the body object
	fmt.Println("\nresponseData is: ", i)

	// Convert the body to a string
	responseString := string(responseData)

	// Echo the current type of the body object
	i = reflect.TypeOf(responseString)
	fmt.Println("\nresponseString is: ", i)

	// Print the string
	fmt.Println("\nPrinting the json response as a plain string: ")
	fmt.Println(responseString)

	var elastic Elastic
	elastic,err := json.Unmarshal(responseData, &elastic)
	if err != nil { log.Fatal(err) }
	fmt.Println(elastic.Status
}

But this is currently give me a:
.go:51: no new variables on left side of :=
and
go:51: assignment count mismatch: 2 = 1

errors.

I’m working my way through the book as well as the Udemy training. I think I get the general idea that for things like this one:

  • Executes the GET request and is returned a byte array.
  • Passes the byte array to ioutil and ReadAll to convert that to a slice of unsigned int8 values.
  • It is at this point that we can then invoke the json.Unmarshal method to (and this is where it gets fuzzy for me ), extract values from the response.Body according to whichever json keys are defined in my custom ‘type’ ( struct ) and all other fields are just stripped off and lost.

If this is correct, then where I am fuzzy is in understanding how to assign the resultant values, whose keys match my struct’s, BACK to a variable or object so I can then use that object and its properties to work with the values I need.

Any help would be greatly appreciated - thanks.

EDIT/UPDATE:

Ok, I figured out what I was doing wrong. The bottom section should be:-

var elastic Elastic
err = json.Unmarshal(responseData, &elastic)
if err != nil { log.Fatal(err) }

fmt.Println("Elastic Status:", elastic.Status)
fmt.Println("Elastic Name:", elastic.Name)
fmt.Println("Elastic Cluster:", elastic.Cluster)
fmt.Println("Elastic Tagline:", elastic.Tagline)

This does now show the expected values. Awesome! But… now I am stuck again trying to work out how to unmarshall this:-

{
  "status" : 200,
  "name" : "Elektro",
  "cluster_name" : "elasticsearch",
  "version" : {
    "number" : "1.7.6",
    "build_hash" : "c730b59357f8ebc555286794dcd90b3411f517c9",
    "build_timestamp" : "2016-11-18T15:21:16Z",
    "build_snapshot" : false,
    "lucene_version" : "4.10.4"
  },
  "tagline" : "You Know, for Search"
}

As you can see, I am just playing around with the basic fields from a simple GET to the ES base endpoint. But what I cannot see is how to extract:

 "version" : {
    "number" : "1.7.6",
    "build_hash" : "c730b59357f8ebc555286794dcd90b3411f517c9",
    "build_timestamp" : "2016-11-18T15:21:16Z",
    "build_snapshot" : false,
    "lucene_version" : "4.10.4"
  }

So, lets say I just want to get: version.number how would I unmarshal that?

Again… very much appreciate any assistance.

Check this out: https://mholt.github.io/json-to-go/

You paste in JSON and it spits out a go struct for that json. Super handy. Should also give you an idea of how to get the version. This will give you a nested struct but you could break it out into its own Version type so you end up with something like:

type Elastic struct {
    Version Version `json:"version"`
}
type Version struct {
    Number string `json:"number"`
    //...
}
1 Like

@joncalhoun
Thank you very much - that helped immensely.

That json-to-go page spat out a struct which contained another struct with the embedded Version values. Worked perfectly and gave me an “of course!” moment. I’m really impressed with how things are going with Go, seems like you can get a lot done pretty easily.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.