Parsing json response


(Yujin Boby) #1

I want to parse result of command

az account list-locations

This command returns a json response

https://pastebin.com/raw/jeZ4LMP2

What i need is list all locations where Microsoft Azure is available.

I am new to golang, here is what i have done so far.

package main

import "fmt"
import "os"
import "os/exec"
import "encoding/json"

type AzureLocation struct {
	displayName string
	id string
	latitude string
	longitude string
	name string
	subscriptionId string
}

func main() {

	cmdOut, err := exec.Command("az", "account", "list-locations").Output()
	
	if (err != nil) {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

	bytes := cmdOut

	var azureLocations []AzureLocation
	json.Unmarshal(bytes, &azureLocations)

	fmt.Println(string(azureLocations));
}

Can anyone help me print all locations. I need to loop through the array and priend fields displayName and name.


( Kvaz1r) #2

Not sure that I understand what exactly do you need.
Just iterate through your slice and print value of fields.

Example: https://play.golang.org/p/js0A9elNJl-


(Yujin Boby) #3

Thanks for the reply, this is what i need, but i need the string read from the command line. SInce you may not have the the azure cli, i tried to replace the jsaon data source with a URL, here is the code

https://play.golang.org/p/bSKqlUbbKV3

Can you please tell why i am getting the error

prog.go:39:6: no new variables on left side of :=


(Ignacio Gómez) #4

As the error says, err is already declared and you can’t redeclare it. Assign to it instead by changing := to =.


(Yujin Boby) #5

Thanks, that fixed it.

Some times azure cli returns differnt type of json object. For example, when i create a Virtual Machine, if sucess, it return one type of json string, that include server IP, server name, etc… If it fail for some reason, the structure of JSON string returned is differnt. How can i handle such situations ?


( Kvaz1r) #6

That’s still a bit unclear for me. If, in any case, all that you need it’s to get value from special field from response - use special library.

For example this one https://github.com/thedevsaddam/gojsonq

Code:

package main

import (
	"fmt"

	"github.com/thedevsaddam/gojsonq"
)

var jsonData string = `[
  {
    "displayName": "East Asia",
    "id": "/subscriptions/da87b641-e192-4863-a66a-40e11b8741f7/locations/eastasia",
    "latitude": "22.267",
    "longitude": "114.188",
    "name": "eastasia",
    "subscriptionId": null
  },
  {
    "displayName": "Southeast Asia",
    "id": "/subscriptions/da87b641-e192-4863-a66a-40e11b8741f7/locations/southeastasia",
    "latitude": "1.283",
    "longitude": "103.833",
    "name": "southeastasia",
    "subscriptionId": null
  }]`

func main() {
	data := gojsonq.New().JSONString(jsonData).Only("name", "displayName")

	for i, t := range data.([]interface{}) {
		v := t.(map[string]interface{})
		fmt.Println(i, "=>", v["name"], v["displayName"])
	}
}

Output:

0 => eastasia East Asia
1 => southeastasia Southeast Asia

(Johan Dahl) #7

Hi. Is it completely different or is just some fields not populated?


(Yujin Boby) #8

Thanks @GreyShatter, i will try that.

@johandalabacka yes, it is differnt. Here is what you get when you have an error

boby@sok-01:~$ az vm create \
>     --resource-group myResourceGroupAutomate \
>     --name myVM \
>     --image UbuntuLTS \
>     --admin-username boby \
>     --admin-password password123 \
>     --location eastasia
Deployment failed. Correlation ID: 2cd9a3ce-43c2-4bad-bf3a-9a137a8deb9d. {
  "error": {
    "code": "SkuNotAvailable",
    "message": "The requested size for resource '/subscriptions/da87b641-e192-4863-a66a-40e11b8741f7/resourceGroups/myResourceGroupAutomate/providers/Microsoft.Compute/virtualMachines/myVM' is currently not available in location 'eastasia' zones '' for subscription 'da87b641-e192-4863-a66a-40e11b8741f7'. Please try another size or deploy to a different location or zones. See https://aka.ms/azureskunotavailable for details."
  }
}
boby@sok-01:~$ 

if VM created properly, you get something like

{
  "fqdns": "",
  "id": "/subscriptions/da87b641-e192-4863-a66a-40e11b8741f7/resourceGroups/myResourceGroupAutomate/providers/Microsoft.Compute/virtualMachines/myVM",
  "location": "eastus",
  "macAddress": "00-0D-3A-4E-B4-09",
  "powerState": "VM running",
  "privateIpAddress": "10.0.0.4",
  "publicIpAddress": "23.96.107.26",
  "resourceGroup": "myResourceGroupAutomate",
  "zones": ""
}

(Johan Dahl) #9

You could make a structure which is a merge of these two responses:

type Reply struct {
	Fqdns            string `json:"fqdns"`
	ID               string `json:"id"`
	Location         string `json:"location"`
	MacAddress       string `json:"macAddress"`
	PowerState       string `json:"powerState"`
	PrivateIPAddress string `json:"privateIpAddress"`
	PublicIPAddress  string `json:"publicIpAddress"`
	ResourceGroup    string `json:"resourceGroup"`
	Zones            string `json:"zones"`
	Error            struct {
		Code    string `json:"code"`
		Message string `json:"message"`
	} `json:"error"`
}

And then check if Error.Code is an empty string or not.