json - 在 GO 语言中使用 API 时如何将 JSON 转换为 Go 类型定义
问题描述
我正在构建一个使用 API 的应用程序,然后还将 json 数据保存到 go lang 结构中,然后我将创建端点,为某些计算提供结果。我已经实现了使用 API,具有挑战性的部分是如何以一种可以理解的方式保存数据。哪种方法合适?
以下是我发出请求时的 JSON 格式。key
我感兴趣的只是Time Series (1min)
JSON
{
"Meta Data": {
"1. Information": "Intraday (1min) prices and volumes",
"2. Symbol": "MSFT",
"3. Last Refreshed": "2018-05-24 16:00:00",
"4. Interval": "1min",
"5. Output Size": "Compact",
"6. Time Zone": "US/Eastern"
},
"Time Series (1min)": {
"2018-05-24 16:00:00": {
"1. open": "98.3050",
"2. high": "98.3600",
"3. low": "98.2500",
"4. close": "98.3100",
"5. volume": "2377114"
},
"2018-05-24 15:59:00": {
"1. open": "98.2900",
"2. high": "98.3300",
"3. low": "98.2900",
"4. close": "98.3000",
"5. volume": "137133"
},
"2018-05-24 15:58:00": {
"1. open": "98.2900",
"2. high": "98.3000",
"3. low": "98.2600",
"4. close": "98.2900",
"5. volume": "135875"
},
"2018-05-24 15:53:00": {
"1. open": "98.2750",
"2. high": "98.2950",
"3. low": "98.2600",
"4. close": "98.2700",
"5. volume": "77959"
}
}
}
代码
package main
import (
"fmt"
"io/ioutil"
"net/http"
"github.com/jmoiron/jsonq"
)
func main() {
response, err := http.Get("https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol=MSFT&interval=1min&apikey=demo")
if err != nil {
fmt.Printf("The HTTP request failed with error %s\n", err)
} else {
data, _ := ioutil.ReadAll(response.Body)
// fmt.Println(string(data))
}
}
解决方案
不幸的是,这些数据的结构很差,无法通过 golang JSON 基础架构轻松解组。
解组数据(例如此示例)的一般方法是定义一个类型(或一组类型),其中包含您想要的结构并使用逻辑实现json.Unmarshaler
接口以检查传入结构并手动填充所需的结构。
例如:
type Quote struct {
Time string
Open, High, Low, Close float32
Volume int
}
type Quotes []Quote
func main() {
qs := Quotes{}
err := json.Unmarshal([]byte(jsonstr), &qs)
if err != nil {
panic(err)
}
fmt.Printf("%#v\n", qs)
}
const targetName = "Time Series (1min)"
func (qs *Quotes) UnmarshalJSON(bs []byte) error {
// Unmarshal into a generic map
obj := make(map[string]interface{})
err := json.Unmarshal(bs, &obj)
if err != nil {
return err
}
// Find the target time series
entries, ok := obj[targetName].(map[string]interface{})
if !ok {
return fmt.Errorf("cannot find entry with name %q", targetName)
}
// Parse a Quote object from each entry in the target object
quotes := []Quote{}
for timestamp, values := range entries {
values, ok := values.(map[string]interface{})
if !ok {
return fmt.Errorf("value for %q is not an object", timestamp)
}
quote := Quote{}
quote.Time = timestamp
v, err := strconv.ParseFloat(values["1. open"].(string), 32)
if err != nil {
return err
}
quote.Open = float32(v)
// Repeat for each of Close,High,Low,Volume...
quotes = append(quotes, quote)
}
*qs = Quotes(quotes)
return nil
}
推荐阅读
- c# - 尝试从 c# 调用 VB6 应用程序时出现文件/访问错误
- python - 如何从整个数据框中删除所有非数字数字:调试
- javascript - 是否可以通过js中的fullCalendar拖放一整天(全天事件)
- html - Shinydashboard:将主标题标题与侧边栏一起折叠
- c# - 数据网格文本框值未使用 ObservableCollection 更新
- python-3.x - 如何在不阻塞整个应用程序的情况下读取单个击键?
- javascript - 地理数据解决方案下拉生成器的问题
- r - Rdieharder 文本文件作为输入
- blockchain - Corda Vault 查询(Java 代码)需要什么导入
- java - 使用 Arraylist 在 Java 中创建登录系统