使用Go进行API请求并解析JSON响应

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

Api Request With Go Parse Json Response

问题

写我的第一个Go应用程序,我正在学习如何进行基本的API调用并解析JSON响应。我相当确定我没有正确地进行类型转换,我的响应是错误的。

如果我创建一些包含数据的数组,我可以得到正确的响应,但是当我将这个更复杂的JSON响应添加到混合中时,事情变得更加混乱,这让我相当确定我没有正确地进行类型转换。

这是我目前的代码,在尝试破坏和尝试解决问题的过程中进行了一些调整:

package main

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

type Payload struct {
	Results []Data
}

type Data struct {
	PosterPath       string  `json:"poster_path"`
	Adult            bool    `json:"adult"`
	Overview         string  `json:"overview"`
	ReleaseDate      string  `json:"release_date"`
	GenreIDs         []int   `json:"genre_ids"`
	ID               int     `json:"id"`
	OriginalTitle    string  `json:"original_title"`
	OriginalLanguage string  `json:"original_language"`
	Title            string  `json:"title"`
	BackdropPath     string  `json:"backdrop_path"`
	Popularity       float64 `json:"popularity"`
	VoteCount        int     `json:"vote_count"`
	Video            bool    `json:"video"`
	VoteAverage      float64 `json:"vote_average"`
}

func main() {
	url := "https://api.themoviedb.org/3/movie/top_rated?api_key=####APIKEYHERE######"
	res, err := http.Get(url)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}

	var p Payload
	err = json.Unmarshal(body, &p)
	if err != nil {
		panic(err)
	}

	for _, data := range p.Results {
		fmt.Println(data.PosterPath)
		fmt.Println(data.Adult)
		fmt.Println(data.Overview)
		fmt.Println(data.ReleaseDate)
		fmt.Println(data.GenreIDs)
		fmt.Println(data.ID)
		fmt.Println(data.OriginalTitle)
		fmt.Println(data.OriginalLanguage)
		fmt.Println(data.Title)
		fmt.Println(data.BackdropPath)
		fmt.Println(data.Popularity)
		fmt.Println(data.VoteCount)
		fmt.Println(data.Video)
		fmt.Println(data.VoteAverage)
	}
}

这是JSON响应的样子:

{
    "page": 1,
    "results": [
        {
            "poster_path": "/lIv1QinFqz4dlp5U4lQ6HaiskOZ.jpg",
            "adult": false,
            "overview": "Under the direction of a ruthless instructor, a talented young drummer begins to pursue perfection at any cost, even his humanity.",
            "release_date": "2014-10-10",
            "genre_ids": [
                18,
                10402
            ],
            "id": 244786,
            "original_title": "Whiplash",
            "original_language": "en",
            "title": "Whiplash",
            "backdrop_path": "/6bbZ6XyvgfjhQwbplnUh1LSj1ky.jpg",
            "popularity": 9.685051,
            "vote_count": 1706,
            "video": false,
            "vote_average": 8.36
        }
    ]
}

有几件事引起了我的注意:

当我尝试将浮点数转换为float64时,我对从float32转换的方式感到困惑。

在JSON响应中有一个数组,当尝试进行类型转换时会感到困惑。

"genre_ids": [
    36,
    18,
    53,
    10752
]

希望这可以帮助到你!

英文:

Writing my first Go Application I am learning to make a basic api call and parse the json response. I am pretty sure I am not casting my types correctly and my response is

false
0
0
0
0 false
0

If I create a few arrays with data in them I can get that response but when I add this more complexed json response to the mix things get more confusing which leads me to be quite positive I am not casting correctly.

This is my current code after playing around and changing things in order to break stuff and try and figure things out.

package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
) 
type Payload struct {
results Data 
}
type Data struct {
poster_path string
adult bool
overview string
release_date string
genre_ids int
id int
original_title string
original_language string
title string
backdrop_path string
popularity float64
vote_count int
video bool
vote_average float64
}
type poster_path map[string]string
type adult map[string]bool
type overview map[string]string
type release_date map[string]string
type genre_ids map[string]int
type id map[string]int
type original_title map[string]string
type original_language map[string]string
type title map[string]string
type backdrop_path map[string]string
type popularity map[string]float64
type vote_count map[string]int
type video map[string]bool
type vote_average map[string]float64
func main() {
// http://image.tmdb.org/t/p/w185
url := "https://api.themoviedb.org/3/movie/top_rated?api_key=####APIKEYHERE######"
res, err := http.Get(url)
if err != nil {
panic(err)
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
panic(err)
}
var p Payload
err = json.Unmarshal(body, &p)
if err != nil {
panic(err)
}
fmt.Println(
p.results.poster_path, "\n", p.results.adult,
p.results.overview, "\n", p.results.release_date,
p.results.genre_ids, "\n", p.results.id,
p.results.original_title, "\n", p.results.original_language,
p.results.title, "\n", p.results.backdrop_path,
p.results.popularity, "\n", p.results.vote_count,
p.results.video, "\n", p.results.vote_average,
)
}

This is what the JSON response looks like,

{
"page": 1,
"results": [
{
"poster_path": "/lIv1QinFqz4dlp5U4lQ6HaiskOZ.jpg",
"adult": false,
"overview": "Under the direction of a ruthless instructor, a talented young drummer begins to pursue perfection at any cost, even his humanity.",
"release_date": "2014-10-10",
"genre_ids": [
18,
10402
],
"id": 244786,
"original_title": "Whiplash",
"original_language": "en",
"title": "Whiplash",
"backdrop_path": "/6bbZ6XyvgfjhQwbplnUh1LSj1ky.jpg",
"popularity": 9.685051,
"vote_count": 1706,
"video": false,
"vote_average": 8.36
}
}

A few things that stand out to me,

When I tried to cast the float I was confused about casting from float32 to float64

There is an array inside the json response which was confusing when trying to cast,

"genre_ids": [
36,
18,
53,
10752
], 

答案1

得分: 4

这是一个常见的初学者错误。由于语言设计的原因,encoding/json 包只能将数据解组到导出字段中。

根据 encoding/json 包的说明:
> 为了将 JSON 解组到结构体中,Unmarshal 会将传入的对象键与 Marshal 使用的键进行匹配(可以是结构体字段名或其标签),优先选择精确匹配,但也接受不区分大小写的匹配。
> Unmarshal 只会设置结构体的导出字段。

要导出一个字段,只需将名称的首字母大写。例如:

type Payload struct {
Results Data 
}

而不是

type Payload struct {
results Data 
}
英文:

Is a common beginners mistake. Due to language design, the encoding/json package can only unmarshal into exported fields.

From the encoding/json package:
> To unmarshal JSON into a struct, Unmarshal matches incoming object keys to
> the keys used by Marshal (either the struct field name or its tag),
> preferring an exact match but also accepting a case-insensitive match.
> Unmarshal will only set exported fields of the struct.

To export a field, simply use a capital first letter of the name. Eg.:

type Payload struct {
Results Data 
}

instead of

type Payload struct {
results Data 
}

答案2

得分: 1

首先,你在JSON中的results末尾缺少一个闭合的方括号]

其次,你没有按照接收到的JSON来构建你的结构体。

最后,在处理Unmarshal/marshal时,在每个导出字段的结构体后使用JSON标签,以帮助Go检测适当的字段(如果你根据Unmarshal/marshal如何识别字段的方式命名字段,则不需要这样做)。

type Payload struct {
Page    int
Results []Data 
}
type Data struct {
PosterPath       string  `json:"poster_path"`
Adult            bool    `json:"adult"`
Overview         string  `json:"overview"`
ReleaseDate      string  `json:"release_date"`
GenreIds         []int   `json:"genre_ids"`
Id               int     `json:"id"`
OriginalTitle    string  `json:"original_title"`
OriginalLanguage string  `json:"original_language"`
Title            string  `json:"title"`
BackdropPath     string  `json:"backdrop_path"`
Popularity       float64 `json:"popularity"`
VoteCount        int     `json:"vote_count"`
Video            bool    `json:"video"`
VoteAverage      float64 `json:"vote_average"`
}

请注意,GenreIds也必须是[]int以匹配JSON数据。在Go中不使用驼峰命名法是一个好主意。

参考:https://play.golang.org/p/VduPD9AY84

英文:

First of all, you are missing a closing square bracket ] at the end of results in your JSON.

Secondly, you did not structure your structs according to the JSON you receive.

Lastly, use JSON tags after each exported field in your struct when dealing with Unmarshal/marshaling to help Go detect the appropriate fields (not necessary if you name the fields according to how Unmarshal/marshal identify fields.

type Payload struct {
Page    int
Results []Data 
}
type Data struct {
PosterPath       string  `json:"poster_path"`
Adult            bool    `json:"adult"`
Overview         string  `json:"overview"`
ReleaseDate      string  `json:"release_date"`
GenreIds         []int   `json:"genre_ids"`
Id               int     `json:"id"`
OriginalTitle    string  `json:"original_title"`
OriginalLanguage string  `json:"original_language"`
Title            string  `json:"title"`
BackdropPath     string  `json:"backdrop_path"`
Popularity       float64 `json:"popularity"`
VoteCount        int     `json:"vote_count"`
Video            bool    `json:"video"`
VoteAverage      float64 `json:"vote_average"`
}

Note that GenreIds has to be []int to match the JSON data as well. And it's a good idea not to use CamelCase in Go.

See https://play.golang.org/p/VduPD9AY84

huangapple
  • 本文由 发表于 2016年3月11日 14:52:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/35933978.html
匿名

发表评论

匿名网友

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

确定