因此,我试图弄清楚如何从https://api.coinmarketcap.com/v1/ticker/ethereum获取以下代码来正确解析JSON数据。在http://echo.jsontest.com/key1/value1/key2/value2的响应中解码JSON数据似乎没有问题,但只有在指向CoinMarketCap API时才会获得空/零值。
package main
import(
"encoding/json"
"net/http"
"log"
)
type JsonTest struct {
Key1 string
Key2 string
}
type CoinMarketCapData struct {
Id string
Name string
Symbol string
Rank int
PriceUSD float64
PriceBTC float64
Volume24hUSD float64
MarketCapUSD float64
AvailableSupply float64
TotalSupply float64
PercentChange1h float32
PercentChange24h float32
PercentChange7d float32
}
func getJson(url string, target interface{}) error {
client := &http.Client{}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Content-Type", "application/json")
r, err := client.Do(req)
if err != nil {
return err
}
defer r.Body.Close()
return json.NewDecoder(r.Body).Decode(target)
}
func main() {
//Test with dummy JSON
url1 := "http://echo.jsontest.com/key1/value1/key2/value2"
jsonTest := new(JsonTest)
getJson(url1, jsonTest)
log.Printf("jsonTest Key1: %s", jsonTest.Key1)
//Test with CoinMarketCap JSON
url2 := "https://api.coinmarketcap.com/v1/ticker/ethereum"
priceData := new(CoinMarketCapData)
getJson(url2, priceData)
//Should print "Ethereum Id: ethereum"
log.Printf("Ethereum Id: %s", priceData.Id)
}
我怀疑它与CoinMarketCap中的JSON位于顶级JSON数组中的事实有关,但我尝试了各种迭代:
priceData := make([]CoinMarketCapData, 1)
无济于事。非常感谢任何建议,谢谢。
答案 0 :(得分:0)
JSON是一个数组,因此您需要将数组传递给Decode方法。还记得检查返回的错误。
package main
import(
"encoding/json"
"net/http"
"log"
)
type CoinMarketCapData struct {
Id string
Name string
Symbol string
Rank int
PriceUSD float64
PriceBTC float64
Volume24hUSD float64
MarketCapUSD float64
AvailableSupply float64
TotalSupply float64
PercentChange1h float32
PercentChange24h float32
PercentChange7d float32
}
func getJson(url string, target interface{}) error {
client := &http.Client{}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Content-Type", "application/json")
r, err := client.Do(req)
if err != nil {
return err
}
defer r.Body.Close()
return json.NewDecoder(r.Body).Decode(target)
}
func main() {
//Test with CoinMarketCap JSON
url2 := "https://api.coinmarketcap.com/v1/ticker/ethereum"
priceData := make([]CoinMarketCapData, 0)
err := getJson(url2, &priceData)
if err != nil {
log.Printf("Failed to decode json: %v", err)
} else {
//Should print "Ethereum Id: ethereum"
log.Printf("Ethereum Id: %v", priceData[0].Id)
}
}
运行此打印
2016/08/21 17:15:27 Ethereum Id: ethereum
答案 1 :(得分:0)
您是对的,顶级API响应类型是一个列表,必须在解组过程中反映出来。解决此问题的一种方法是将 MarketCap 响应定义为切片,如下所示:
package main
import (
"encoding/json"
"log"
"net/http"
)
// curl -sLf "https://api.coinmarketcap.com/v1/ticker/ethereum" | JSONGen
// command line helper: `go get github.com/bemasher/JSONGen`
type MarketCapResponse []struct {
AvailableSupply float64 `json:"available_supply"`
HVolumeUsd float64 `json:"24h_volume_usd"`
Id string `json:"id"`
MarketCapUsd float64 `json:"market_cap_usd"`
Name string `json:"name"`
PercentChange1h float64 `json:"percent_change_1h"`
PercentChange24h float64 `json:"percent_change_24h"`
PercentChange7d float64 `json:"percent_change_7d"`
PriceBtc float64 `json:"price_btc"`
PriceUsd float64 `json:"price_usd"`
Rank int64 `json:"rank"`
Symbol string `json:"symbol"`
TotalSupply float64 `json:"total_supply"`
}
然后解编就行了。需要注意的一点是指向切片的指针与切片不同。特别是,指针不支持索引,这就是为什么需要首先取消引用它来访问列表中的第一个项目。
func getAndUnmarshal(url string, target interface{}) error {
var client = &http.Client{}
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Content-Type", "application/json")
r, _ := client.Do(req)
defer r.Body.Close()
return json.NewDecoder(r.Body).Decode(target)
}
func main() {
link := "https://api.coinmarketcap.com/v1/ticker/ethereum"
resp := new(MarketCapResponse)
getAndUnmarshal(link, resp)
log.Printf("Ethereum Id: %s", (*resp)[0].Id)
// prints:
// 2016/08/22 02:13:23 Ethereum Id: ethereum
}
另一种方法是为单个 MarketCap 定义一个类型,然后在需要时创建一个切片作为目标:
package main
// curl -sLf "https://api.coinmarketcap.com/v1/ticker/ethereum" | jq .[0] | JSONGen
type MarketCap struct {
AvailableSupply float64 `json:"available_supply"`
HVolumeUsd float64 `json:"24h_volume_usd"`
Id string `json:"id"`
MarketCapUsd float64 `json:"market_cap_usd"`
Name string `json:"name"`
PercentChange1h float64 `json:"percent_change_1h"`
PercentChange24h float64 `json:"percent_change_24h"`
PercentChange7d float64 `json:"percent_change_7d"`
PriceBtc float64 `json:"price_btc"`
PriceUsd float64 `json:"price_usd"`
Rank int64 `json:"rank"`
Symbol string `json:"symbol"`
TotalSupply float64 `json:"total_supply"`
}
func getAndUnmarshal(url string, target interface{}) error {
...
}
func main() {
link := "https://api.coinmarketcap.com/v1/ticker/ethereum"
resp := make([]MarketCap, 0)
getAndUnmarshal(link, &resp)
log.Printf("Ethereum Id: %s", resp[0].Id)
// 2016/08/22 02:13:23 Ethereum Id: ethereum
}
更适合您的将取决于您的使用案例。如果您希望结构体反映API响应,那么第一种方法似乎更合适。 MarketCap 是一个东西,而API只是一种访问它的方式,而不是第二种方式更合适,我相信。