Converting a complex http json response array to a simple struct slice without creating several structs to match the response using Go

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

Converting a complex http json response array to a simple struct slice without creating several structs to match the response using Go

问题

如果一个 HTTP 响应的格式不是直接的对象列表,我唯一能想到的将其转换为结构体的方法是创建两个结构体,以匹配响应的确切格式。有没有更简洁的方法,我只需创建一个 Product 结构体,而不需要创建 ProductRes 包装结构体?

以下是我调用的 API 返回的响应示例:

{
    "items": [
        {
            "name": "Product 1",
            "price": 20.45
        },
        {
            "name": "Product 2",
            "price": 31.24
        }
    ]
}

这是我创建的两个结构体,用于将 API 响应转换为 Product 切片:

type Product struct {
    Name  string  `json:"name"`
    Price float64 `json:"price"`
}

type ProductRes struct {
    Items []Product `json:"items"`
}

这是部分代码,用于发起 API 请求并将响应转换为 Product 切片:

req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
    log.Fatalln(err)
}

resp, err := c.client.Do(req)
if err != nil {
    log.Fatalln(err)
}

defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
    log.Fatalln(err)
}

products := ProductRes{}

// 这一行让我觉得我实际上确实需要多个结构体,除非我可以在发送之前修改 body
json.Unmarshal(body, &products)

希望这能帮到你!如果你有任何其他问题,请随时问我。

英文:

If an http response comes in a format that is not directly a list of objects the only way I could figure out how to convert them to structs is by creating two structs to match the exact format of the response. Is there anyway to do this cleaner where I can just create a Product struct and don't need to create the ProductRes wrapper struct?

Below is an example of what the response from the api I am calling looks like:

{
	"items": [
		{
			"name": "Product 1",
			"price": 20.45
		},
		{
			"name": "Product 2",
			"price": 31.24
		}
		    
	]
}

Here are the two structs I create to convert the api response to a slice of Product:

type Product struct {
	Name          string  `json:"name"`
	Price         float64 `json:"price"`
}

type ProductRes struct {
	Items []Product `json:"items"`
}

Here is part of the code to make the api request and convert the response to a slice of Product:

req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
	log.Fatalln(err)
}

resp, err := c.client.Do(req)
if err != nil {
	log.Fatalln(err)
}

defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
	log.Fatalln(err)
}

products := ProductRes{}

// This line makes me think I actually do need multiple structs, unless I can modify body somehow prior to sending it in here
json.Unmarshal(body, &products)

答案1

得分: 3

你可以通过使用匿名类型来消除声明的类型ProductRes

var wrapper struct { Items []Product }
err := json.Unmarshal(body, &wrapper)
if err != nil { 
   // TODO: 处理错误
}

products := wrapper.Items

你也可以使用map:

var m map[string][]Product
err := json.Unmarshal(body, &m)
if err != nil { 
   // TODO: 处理错误
}
products := m["items"]
英文:

You can eliminate the declared type ProductRes by using an anonymous type:

var wrapper struct { Items []Product }
err := json.Unmarshal(body, &wrapper)
if err != nil { 
   // TODO: handle error
}

products := wrapper.Items

You can also use a map:

var m map[string][]Product
err := json.Unmarshal(body, &m)
if err != nil { 
   // TODO: handle error
}
products := m["items"]

huangapple
  • 本文由 发表于 2021年10月29日 10:47:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/69763032.html
匿名

发表评论

匿名网友

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

确定