bugfix> json > 投稿

APIを使用し、jsonデータを保存して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))
    }
}

回答 1 件
  • 残念ながら、このデータは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
    }
    
    

あなたの答え