【问题标题】:Convert JSON array API response to a struct将 JSON 数组 API 响应转换为结构
【发布时间】:2021-08-02 20:01:11
【问题描述】:

使用 Go,我希望查询 API 端点并将结果输出到 Gorm SQLite DB。这在(here)之前已经完成了,但是我需要自己写代码。

API 端点返回一个 JSON 数组,对于数组中的每笔交易,我想将其放入一个结构中,然后将其作为行添加到 SQLite 数据库中。

结构体定义如下:

type Trade struct {
    TradeID      int64  `json:"id"`
    Price        string `json:"price"`
    Qty          string `json:"qty"`
    QuoteQty     string `json:"quoteQty"`
    Time         int64  `json:"time"`
    IsBuyerMaker bool   `json:"isBuyerMaker"`
    IsBestMatch  bool   `json:"isBestMatch"`
}

这些类型可能看起来很奇怪,但它们是通过使用 PowerShell 和以下代码确定的:

PS C:\Git> $body = @{"symbol" = "ETHEUR";"limit" = 1000}
PS C:\Git> $response = Invoke-RestMethod https://api.binance.com/api/v3/trades -Body $body
PS C:\Git> $response[0] | gm

   TypeName: System.Management.Automation.PSCustomObject

Name         MemberType   Definition
----         ----------   ----------
Equals       Method       bool Equals(System.Object obj)
GetHashCode  Method       int GetHashCode()
GetType      Method       type GetType()
ToString     Method       string ToString()
id           NoteProperty long id=21731777
isBestMatch  NoteProperty bool isBestMatch=True
isBuyerMaker NoteProperty bool isBuyerMaker=True
price        NoteProperty string price=3539.03000000
qty          NoteProperty string qty=0.28600000
quoteQty     NoteProperty string quoteQty=1012.16258000
time         NoteProperty long time=1620822731248

所以,我目前的Go函数如下:


func getTrade(symbol string, limit int) {
    uri := fmt.Sprintf("https://api.binance.com/api/v3/trades?symbol=%v&limit=%v", symbol, limit)

    db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
    if err != nil {
        panic("failed to connect database")
    }

    // Create the fields in the database based on the Trade Struct
    db.AutoMigrate(&Trade{})

    // Query Binance API endpoint
    response, err := http.Get(uri)

    // Log if an error occurred
    if err != nil {
        log.Fatalln(err)
    }

    // Defer closing object
    defer response.Body.Close()

    // Create trade struct
    trade := Trade{}

从这里我尝试了几种将响应转换为结构的方法,但都失败了。这些方法包括:

// Unmarshal bytes to data struct
    _ = json.Unmarshal([]byte(responseData), &trade)
var myClient = &http.Client{Timeout: 10 * time.Second}

func getJson(url string, target interface{}) error {
    response, err := myClient.Get(url)
    if err != nil {
        return err
    }
    defer response.Body.Close()

    return json.NewDecoder(response.Body).Decode(target)
}
// Iterate through trades returned (this doesn't work)
    for _, trade := range responseData {
        tradeVariable := Trade{}
        tradeVariable.TradeID = trade.id
        fmt.Println(tradeVariable.TradeID)
    }

我感觉真的被困住了,好像我错过了与编组有关的东西,有人可以帮我吗?

【问题讨论】:

  • 对于包含对象的 json 数组,您应该使用 Go 结构切片,而不是 只是 结构。即trades := []Trade{} 并将&trades 传递给json.Unmarshal 并确保不要丢弃_ 的错误,而是正确检查并处理它。如果结构体的字段类型有问题,json.Unmarshal 返回的错误会非常清楚地告诉您。

标签: arrays json go


【解决方案1】:

由于 JSON 响应是一个数组,因此您需要将其解组为一个结构切片。确保您还使用了正确的 Go 类型。对 JSON 数字使用 float64

type Trade struct {
    TradeID      float64 `json:"id"`
    Price        string  `json:"price"`
    Qty          string  `json:"qty"`
    QuoteQty     string  `json:"quoteQty"`
    Time         float64 `json:"time"`
    IsBuyerMaker bool    `json:"isBuyerMaker"`
    IsBestMatch  bool    `json:"isBestMatch"`
}

func main() {
    symbol := "ETHEUR"
    limit := 1000
    uri := fmt.Sprintf("https://api.binance.com/api/v3/trades?symbol=%v&limit=%v", symbol, limit)
    response, err := http.Get(uri)
    if err != nil {
        fmt.Println(err)
    }
    body, err := ioutil.ReadAll(response.Body)
    if err != nil {
        fmt.Println(err)
    }
    defer response.Body.Close()
    trade := []Trade{}
    err = json.Unmarshal([]byte(body), &trade)
    if err != nil {
        fmt.Println(err)
    }
    fmt.Println(trade)
}

【讨论】:

    【解决方案2】:

    如果我们有一个 json 样本(模拟)来了解由于 json 是否存在确切的问题,这可能会有所帮助。

    我怀疑因为你有一个你之前提到的结构的数组,你应该对[]Trade{}而不是Trade{}进行解组 最后,对于 json 类型,当您进行解组时,有一种规则集,但仅当您的字段类型为 interface{} 时:

    source

    【讨论】:

      【解决方案3】:

      如果您正在获取 json 数组,我认为它们是 json 对象数组,并且每个对象都包含根据您定义的结构的 json。类似于下面的示例。

      [
        {
          "id": 1,
          "price": "111",
          "qty": "20",
          "quoteQty": "100",
          "time": 6039484,
          "isBuyerMaker": true,
          "isBestMatch": false
        },
        {
          "id": 2,
          "price": "222",
          "qty": "20",
          "quoteQty": "100",
          "time": 6039484,
          "isBuyerMaker": true,
          "isBestMatch": false
        },
        {
          "id": 3,
          "price": "333",
          "qty": "20",
          "quoteQty": "100",
          "time": 6039484,
          "isBuyerMaker": true,
          "isBestMatch": false
        }
      ]
      

      在您的代码中,您需要执行这些操作。

      1. 声明一个 Trade 结构,
      2. 将此数据的 json 解组到该切片中
      3. 遍历切片以获取每个 json 对象的处理程序。
      4. 现在您可以形成一个 sql 查询并访问每个 json 对象的 json 值并对数据库进行查询。

      类似的东西。

      // Assuming r is your default http.Request handler, get the complete request body
      byteSlice, err := ioutil.ReadAll(r.Body)
          if err != nil {
              log.Println("Error in reading request body")
          }
      
      var trades []Trade
      
      if err = json.Unmarshal(byteSlice, &trades); err != nil {
              log.Println("Error in json unmarshal")
              http.Error(w, err.Error(), http.StatusBadRequest)
              return
          }
      
      for _, trade := range trades {
              log.Println("Trade ID: ", trade.TradeID)
              // Call a function and pass each trade object
              err := triggerSQLQuery(trade)
              if err != nil {
                log.Println(err.Error())
              }
          }
      
      
      func triggerSQLQuery(trade Trade) error {
        // Access trade object and form an sql query and execute it.
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-08-09
        • 1970-01-01
        相关资源
        最近更新 更多