0

I am new to GoLang, and have a question about filling an array from nested JSON data. I have looked through Stack overflow yesterday and cannot find this exact topic, only threads that are similar, but do not provide a direct solution.

Lets say I have some nested JSON data like what is given below:

How can I create a nested struct to fill an array of the close prices. My code is given below. My goal is to have an array where, arr = {157.92, 142.19, 148.26}

Thanks in advance! I greatly appreciate any help!

{
  "history": {
    "day": [
      {
        "date": "2019-01-02",
        "open": 154.89,
        "high": 158.85,
        "low": 154.23,
        "close": 157.92,
        "volume": 37039737
      },
      {
        "date": "2019-01-03",
        "open": 143.98,
        "high": 145.72,
        "low": 142.0,
        "close": 142.19,
        "volume": 91312195
      },
      {
        "date": "2019-01-04",
        "open": 144.53,
        "high": 148.5499,
        "low": 143.8,
        "close": 148.26,
        "volume": 58607070
      }
      ...
    ]
  }
}
// DATA STRUCTURE
type Hist struct {
    History string `json:"history"`
}

type Date struct {
    Day string `json:"day"`
}

type Price struct {
    Close []string `json:"close"`
}

// HISTORICAL QUOTES
func get_quotes(arg1 string, arg2 string, arg3 string, arg4 string) []string {

    // arg1 = ticker symbol, arg2 = start, arg3 = end, arg4 = access token

    // TRADIER API
    apiUrl := "https://sandbox.tradier.com/v1/markets/history?symbol=" + arg1 + "&interval=daily&start=" + arg2 + "&end=" + arg3

    u, _ := url.ParseRequestURI(apiUrl)
    urlStr := u.String()

    client := &http.Client{}
    r, _ := http.NewRequest("GET", urlStr, nil)
    r.Header.Add("Authorization", "Bearer "+arg4)
    r.Header.Add("Accept", "application/json")

    resp, _ := client.Do(r)
    responseData, err := ioutil.ReadAll(resp.Body)

    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(resp.Status)
    fmt.Println(string(responseData))

    var response Price
    json.NewDecoder(resp.Body).Decode(&response)

    fmt.Println(response.Close)

    return response.Close

}
5
  • 2
    "I have looked through Stack overflow yesterday and cannot find this exact topic, only threads that are similar, but do not provide a direct solution." Have you tried implementing your own solution? Can you show that code? SO isn't a code-writing service. Commented Jun 3, 2021 at 19:03
  • 2
    The "day" field of your JSON does not contain a JSON object (in which the decode could match the key "close"); instead, it contains a list. You basically have two options here: 1) unmarshal the value of "day" to a slice of struct types each containing a single field of type string tagged json:"close", and then post-process the result: walk the resulting slice and extract the values from the slice's elements; 2) Use the "streaming" facility of the JSON decoder to walk the list value and produce the resulting slice on the go. I strongly recommend to stick to the 1st approach for now. Commented Jun 3, 2021 at 19:21
  • 2
    The language is called Go—for basically the same reason you do not say PytongLang, JavaScriptLang etc. Commented Jun 3, 2021 at 19:22
  • @Adrian Yes, I have tried implementing my own solution, its attached above. Commented Jun 3, 2021 at 19:25
  • @kostix Can you provide an example, I am not quite sure I understand Commented Jun 3, 2021 at 19:27

1 Answer 1

4

Something like this should give you what you need. Your data structure does not correctly reflect the response from the API. I used this tool to quickly convert the JSON value into a Go struct type. Once you're decoding the response correctly, then it's just a matter of iterating over each Day struct and appending the close value to an output array.

I added the core stuff for decoding and mapping the values. You can handle customizing the client, request, and headers however you'd like by combining what you've already got.

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "net/http"
)

type Response struct {
    History History `json:"history"`
}
type Day struct {
    Date   string  `json:"date"`
    Open   float64 `json:"open"`
    High   float64 `json:"high"`
    Low    float64 `json:"low"`
    Close  float64 `json:"close"`
    Volume int     `json:"volume"`
}
type History struct {
    Day []Day `json:"day"`
}

func main() {
    prices, err := closePrices()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(prices)
}

func closePrices() (out []float64, err error) {
    resp, err := http.Get("...")
    if err != nil {
        return
    }
    r := Response{}
    err = json.NewDecoder(resp.Body).Decode(&r)
    if err != nil {
        return
    }
    for _, d := range r.History.Day {
        out = append(out, d.Close)
    }
    return
}
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.