读取和解组Golang中的API结果

huangapple go评论83阅读模式
英文:

Reading and Unmarshalling API results in Golang

问题

在下面的程序中,我从一个API中提取了一些数据。

它输出的是一个相当复杂的数据。
当我使用ioutil.ReadAll(resp.Body)时,结果的类型是[]uint8
如果我尝试读取结果,它只是一个随机的整数数组。

然而,如果我使用string(diskinfo)将其转换为字符串,我就能读取它。
但是我想在一个结构体中使用它,并且在解组时遇到了困难。

package main

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

type ApiResults struct {
	Results []struct {
		StatementID int `json:"statement_id"`
		Series      []struct {
			Name    string `json:"name"`
			Tags    struct {
				Host string `json:"host"`
			} `json:"tags"`
			Columns []string      `json:"columns"`
			Values  []interface{} `json:"values"`
		} `json:"series"`
	} `json:"results"`
}

func main() {
	myURL := "my_url"
	myQuery := fmt.Sprintf("my_query")

	resp, err := http.Get(myURL + url.QueryEscape(myQuery))
	if err != nil {
		fmt.Printf("ERROR: %v\n", err)
	} else {
		fmt.Println(reflect.TypeOf(resp))
		diskInfo, _ := ioutil.ReadAll(resp.Body)
		fmt.Println(reflect.TypeOf(diskInfo))
		fmt.Println(diskInfo)
		fmt.Println(string(diskInfo))
		diskInfoString := string(diskInfo)
		data := ApiResults{}
		json.Unmarshal([]byte(diskInfoString), &data)
		//fmt.Printf("Values = %v\n", data.Results[0].Series[0].Values)
		//fmt.Printf("Server = %v\n", data.Results[0].Series[0].Tags.Host)
	}
}

如果我将数据视为字符串,我会得到以下结果(格式化后):

{
  "results": [
    {
      "statement_id": 0,
      "series": [
        {
          "name": "disk",
          "tags": {
            "host": "myServer1"
          },
          "columns": [
            "time",
            "disk_size"
          ],
          "values": [
            [
              "2021-07-07T07:53:32.291490387Z",
              1044
            ]
          ]
        },
        {
          "name": "disk",
          "tags": {
            "host": "myServer2"
          },
          "columns": [
            "time",
            "disk_size"
          ],
          "values": [
            [
              "2021-07-07T07:53:32.291490387Z",
              1046
            ]
          ]
        }
      ]
    }
  ]
}

我认为我的ApiResults结构体也结构不正确,因为API的结果包含了多个主机的信息。
但首先,我怀疑数据是否必须以不同的格式发送到结构体中。一旦我完成这一步,我可能可以尝试弄清楚如何从结构体中读取数据。

英文:

In the below program I'm extracting some data from an API.

It outputs a rather complex data.
When I ioutil.ReadAll(resp.Body), the result is of type []uint8.
If I try to read the results, its just a random array of integers.

However, I'm able to read it if I convert it to string using string(diskinfo)
But I want to use this in a Struct and having trouble unmarshalling.

package main

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

type ApiResults struct {
	results []struct {
		statement_id int `json.statement_id`
		series       []struct {
			name string `json.name`
			tags struct {
				host string `json.host`
			}
			columns []string      `json.columns`
			values  []interface{} `json.values`
		}
	}
}

func main() {
	my_url := "my_url"
	my_qry := fmt.Sprintf("my_query")

	resp, err := http.Get(my_url + url.QueryEscape(my_qry))
	if err != nil {
		fmt.Printf("ERROR:  %v\n", err)
	} else {
		fmt.Println(reflect.TypeOf(resp))
		diskinfo, _ := ioutil.ReadAll(resp.Body)
		fmt.Println(reflect.TypeOf((diskinfo)))
		fmt.Println(diskinfo)
		fmt.Println(string(diskinfo))
		diskinfo_string := string(diskinfo)
		data := ApiResults{}
		json.Unmarshal([]byte(diskinfo_string), &data)
		//fmt.Printf("Values = %v\n", data.results.series.values)
		//fmt.Printf("Server = %v\n", data.results.series.tags.host)
	}
}

If I view the data as a string, I get this (formatted):

{"results":[
  {"statement_id":0,
   "series":[
    {"name":"disk",
     "tags":{"host":"myServer1"},
     "columns":["time","disk_size"],
     "values":[["2021-07-07T07:53:32.291490387Z",1044]]},
    {"name":"disk",
     "tags":{"host":"myServer2"},
     "columns":["time","disk_size"],
     "values":[["2021-07-07T07:53:32.291490387Z",1046]]}
  ]}
]}

I think my Apireturn struct is also structured incorrectly because the API results have info for multiple hosts.
But first, I doubt if the data has to be sent in a different format to the struct. Once I do this, I can probably try to figure out how to read from the Struct next.

答案1

得分: 2

ioutil.ReadAll已经以byte[]类型的形式提供了数据。因此,你可以直接调用json.Unmarshal并将其作为参数传递。

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
)


func toStruct(res *http.Response) (*ApiResults, error) {
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

    defer res.Body.Close()

	data := ApiResults{}
	if err := json.Unmarshal(body, &data); err != nil {
		return nil, err
	}

	return data, nil 
}

你的结构体似乎也存在问题。使用结构体标签的正确方式如下所示。此外,字段需要被导出以供json.Unmarshal使用的json标签正常工作——以大写字母开头即可。

type ApiResults struct {
    Results []struct {
        StatementId int `json:"statement_id"`
        Series       []struct {
            Name string `json:"name"`
            Tags struct {
                Host string `json:"host"`
            } `json:"tags"`
            Columns []string      `json:"columns"`
            Values  []interface{} `json:"values"`
        } `json:"series"`
    } `json:"results"`
}
英文:

The ioutil.ReadAll already provides you the data in the type byte[]. Therefore you can just call json.Unmarshal passing it as a parameter.

import (
	"encoding/json"
	"io/ioutil"
	"net/http"
)


func toStruct(res *http.Response) (*ApiResults, error) {
	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		return nil, err
	}

    defer res.Body.Close()

	data := ApiResults{}
	if err := json.Unmarshal(body, &data); err != nil {
		return nil, err
	}

	return data, nil 
}

There also seems to be an issue with your struct. The correct way to use struct tags is as follows. Plus, fields need to be exported for the json tag (used by json.Umarshal) to work – starting with uppercase will do it.

type ApiResults struct {
    Results []struct {
        StatementId int `json:"statement_id"`
        Series       []struct {
            Name string `json:"name"`
            Tags struct {
                Host string `json:"host"`
            } `json:"tags"`
            Columns []string      `json:"columns"`
            Values  []interface{} `json:"values"`
        } `json:"series"`
    } `json:"results"`
}

huangapple
  • 本文由 发表于 2021年7月8日 16:15:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/68297891.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定