How to fetch values from JSON in golang - json

i have following piece of code which calls the yahoo finance api to get the stock values for given stock symbol.
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
)
//Response structure
type Response struct {
Query struct {
Count int `json:"count"`
Created string `json:"created"`
Lang string `json:"lang"`
Results struct {
Quote []struct {
LastTradePriceOnly string `json:"LastTradePriceOnly"`
} `json:"quote"`
} `json:"results"`
} `json:"query"`
}
func main() {
var s Response
response, err := http.Get("http://query.yahooapis.com/v1/public/yql?q=select%20LastTradePriceOnly%20from%20yahoo.finance.quote%20where%20symbol%20in%20(%22AAPL%22,%22FB%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys")
if err != nil {
fmt.Printf("%s", err)
os.Exit(1)
} else {
defer response.Body.Close()
contents, err := ioutil.ReadAll(response.Body)
json.Unmarshal([]byte(contents), &s)
fmt.Println(s.Query.Results.Quote)
if err != nil {
fmt.Printf("%s", err)
os.Exit(1)
}
fmt.Printf("%s\n", string(contents))
}
}
fmt.Println(s.Query.Results.Quote) is giving me a multi value array since Quote is a array of structure. For eg: [{52.05},{114.25}]
How should i split it in a single value in golang ?
For eg: 52.05
114.25
Help is highly appreciated.
Thanks

I am new to golang and not aware of many data structures. But i figured out how to get the single value out of array of structure.
fmt.Println(s.Query.Results.Quote[0].LastTradePriceOnly)
this worked for me..I only have to iterate this in a loop to fetch all values.
Thanks.

Related

How to store data from a HTTP Get request in a slice of structs

Problem
I'm new to Go and I'm trying to store json data in a struct from the Gov.uk public holidays API, so I can use this later on in my frontend.
If I run
var sb = string(body)
fmt.Println(sb)
I can see the data that's being returned in my terminal. I know that the response body is made up of bytes and the above converts it to a string.
I would like to iterate through the response body and store the data in a slice of structs called holidays, each struct will contain the data for a single public holiday. For some reason, the holidays variable returns an empty slice: [].
I guess my two questions are:
What's the best way to transform json data into a slice of structs to be used later on?
Why does the holidays variable return an empty slice?
Thanks!
Here's my code below:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
)
type Response struct {
Data []Data
}
type Data struct {
Division string
Bankholiday Bankholiday
}
type Bankholiday struct {
Title string
Date string
}
func main() {
resp, err := http.Get("https://www.gov.uk/bank-holidays.json")
if err != nil {
log.Fatal(err)
}
if resp.Body != nil {
defer resp.Body.Close()
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalln(err)
}
var response Response
json.Unmarshal(body, &response)
var holidays = []Bankholiday{}
for _, date := range response.Data {
holidays = append(holidays, Bankholiday{
Title: date.Bankholiday.Title,
Date: date.Bankholiday.Date,
})
}
fmt.Println("holidays: ", holidays)
}
I had to adjust the Response struct to handle correct unmarshaling of data. Find below the working code:
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
)
type Response map[string]Data
type Data struct {
Division string `json:"division"`
Events []struct {
Title string `json:"title"`
Date string `json:"date"`
Notes string `json:"notes"`
Bunting bool `json:"bunting"`
} `json:"events"`
}
func main() {
resp, err := http.Get("https://www.gov.uk/bank-holidays.json")
if err != nil {
log.Fatal(err)
}
if resp.Body != nil {
defer resp.Body.Close()
}
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Fatalln(err)
}
var response Response
if err = json.Unmarshal(body, &response); err != nil {
log.Fatalln(err)
}
for div, _ := range response {
for _, event := range response[div].Events {
fmt.Printf("Division=%s, Holiday=%s, Date=%s\n", div, event.Title, event.Date)
}
}
}
Because your json fields must match your structs.
type Response map[string]Data
type Data struct {
Division string `json:"division"`
Events []Event `json:"events"`
}
type Event struct {
Title string `json:"title"`
Date string `json:"date"`
Notes string `json:"notes"`
Bunting bool `json:"bunting"`
}

How to extract specific JSON data

I do not know how to select specific JSON data.
How can I change this code so that I have just the id, and none of the other response data?
I read online, and apparently I need to use a struct? I am unsure of how to approach this problem.
package main
import(
"fmt"
"io"
"log"
"net/http"
)
func get_single_product() {
res, err := http.Get("https://api.pro.coinbase.com/products/UNI-USD")
if err != nil {
log.Fatal(err)
}
data, err := io.ReadAll(res.Body)
res.Body.Close()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", data)
}
func main() {
// CALL GET PRODUCTS FUNCTION
get_single_product()
}
This Returns...
{
"id":"UNIUSD",
"base_currency":"UNI",
"quote_currency":"USD",
"base_min_size":"0.1",
"base_max_size":"200000",
"quote_increment":"0.0001",
"base_increment":"0.000001",
"display_name":"UNI/USD",
"min_market_funds":"1.0",
"max_market_funds":"100000",
"margin_enabled":false,
"post_only":false,
"limit_only":false,
"cancel_only":false,
"trading_disabled":false,
"status":"online",
"status_message":""
}
You can use the encoding/json package to decode your json data to an object. Just define the fields you are interested in the object and it will only read out those. Then create a decoder with json.NewDecoder().
package main
import (
"encoding/json"
"fmt"
"log"
"net/http"
)
type Response struct {
ID string `json:"id"`
}
func main() {
res, err := http.Get("https://api.pro.coinbase.com/products/UNI-USD")
if err != nil {
log.Fatal(err)
}
var response Response
json.NewDecoder(res.Body).Decode(&response)
fmt.Println(response.ID)
}
// Output
UNI-USD
See also this question: How to get JSON response from http.Get

Read extern JSON file

I am trying to read the following JSON file:
{
"a":1,
"b":2,
"c":3
}
I have tried this but I found that I had to write each field of the JSON file into a struct but I really don't want to have all my JSON file in my Go code.
import (
"fmt"
"encoding/json"
"io/ioutil"
)
type Data struct {
A string `json:"a"`
B string `json:"b"`
C string `json:"c"`
}
func main() {
file, _ := ioutil.ReadFile("/path/to/file.json")
data := Data{}
if err := json.Unmarshal(file ,&data); err != nil {
panic(err)
}
for _, letter := range data.Letter {
fmt.Println(letter)
}
}
Is there a way to bypass this thing with something like json.load(file) in Python?
If you only want to support integer values, you could unmarshal your data into a map[string]int. Note that the order of a map is not defined, so the below program's output is non-deterministic for the input.
package main
import (
"fmt"
"encoding/json"
"io/ioutil"
)
func main() {
file, _ := ioutil.ReadFile("/path/to/file.json")
var data map[string]int
if err := json.Unmarshal(file ,&data); err != nil {
panic(err)
}
for letter := range data {
fmt.Println(letter)
}
}
You can unmarshal any JSON data in this way:
var data interface{}
if err := json.Unmarshal(..., &data); err != nil {
// handle error
}
Though, in this way you should handle all the reflection-related stuffs
since you don't know what type the root data is, and its fields.
Even worse, your data might not be map at all.
It can be any valid JSON data type like array, string, integer, etc.
Here's a playground link: https://play.golang.org/p/DiceOv4sATO
It's impossible to do anything as simple as in Python, because Go is strictly typed, so it's necessary to pass your target into the unmarshal function.
What you've written could otherwise be shortened, slightly, to something like this:
func UnmarshalJSONFile(path string, i interface{}) error {
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close()
return json.NewDecoder(f).Decode(i)
}
But then to use it, you would do this:
func main() {
data := Data{}
if err := UnmarshalJSONFile("/path/to/file.json", &data); err != nil {
panic(err)
}
}
But you can see that the UnmarshalJSONFile is so simple, it hardly warrants a standard library function.

With Go (golang) how can I Unmarshal data into a struct, and then call specific fields from the struct?

I'm trying to do an API request to get some information from steams public API (this is mainly for learning Go and just learning how to deal with Json / API requests) I have gotten this code so far:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strconv"
)
type SteamAPI struct {
APIKey string
}
type GetAppNews struct {
AppNews struct {
AppId int `json:"appid"`
NewsItems []struct {
Gid int `json:"gid"`
Title string `json:"title"`
Url string `json:"url"`
IsExternalUrl bool `json:"is_external_url"`
Author string `json:"author"`
Contents string `json:"contents"`
Feedlabel string `json:"feedlabel"`
Date int `json:"date"`
} `json:"newsitems"`
} `json:"appnews"`
}
type JsonResponse map[string]GetAppNews
func (s SteamAPI) GetNewsForApp(appid, count, maxlength int) error {
sAppid := strconv.Itoa(appid)
sCount := strconv.Itoa(count)
sMaxlength := strconv.Itoa(maxlength)
resp, err := http.Get("http://api.steampowered.com/ISteamNews/GetNewsForApp/v0002/?appid=" + sAppid + "&count=" + sCount + "&maxlength=" + sMaxlength + "&format=json")
if err != nil {
return err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
var jsonReturn JsonResponse
json.Unmarshal(body, &jsonReturn)
fmt.Println(jsonReturn)
return nil
}
func main() {
Tester := SteamAPI{""}
Tester.GetNewsForApp(440, 3, 300)
}
Things seem to work, alright, I guess but its not formatting it the way I would expect it to Unmarshal. It prints out like this:
map[appnews:{{0 []}}]
You can click here to see exactly what the format of the JSON response looks like, if anybody could tell me what I have done wrong with my struct, in the end I expect to be able to go something like:
fmt.Println(blah["appnews"]["appid"]) and it would return 440.
Thats all I really got to go off of, if you need anymore specific information let me know! Thanks for the help!
The data fits the struct just fine, no need for map[string]GetAppNews.
type JsonResponse map[string]GetAppNews should just be GetAppNews.
playground

Converting Go struct to JSON

I am trying to convert a Go struct to JSON using the json package but all I get is {}. I am certain it is something totally obvious but I don't see it.
package main
import (
"fmt"
"encoding/json"
)
type User struct {
name string
}
func main() {
user := &User{name:"Frank"}
b, err := json.Marshal(user)
if err != nil {
fmt.Printf("Error: %s", err)
return;
}
fmt.Println(string(b))
}
Then when I try to run it I get this:
$ 6g test.go && 6l -o test test.6 && ./test
{}
You need to export the User.name field so that the json package can see it. Rename the name field to Name.
package main
import (
"fmt"
"encoding/json"
)
type User struct {
Name string
}
func main() {
user := &User{Name: "Frank"}
b, err := json.Marshal(user)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(b))
}
Output:
{"Name":"Frank"}
Related issue:
I was having trouble converting struct to JSON, sending it as response from Golang, then, later catch the same in JavaScript via Ajax.
Wasted a lot of time, so posting solution here.
In Go:
// web server
type Foo struct {
Number int `json:"number"`
Title string `json:"title"`
}
foo_marshalled, err := json.Marshal(Foo{Number: 1, Title: "test"})
fmt.Fprint(w, string(foo_marshalled)) // write response to ResponseWriter (w)
In JavaScript:
// web call & receive in "data", thru Ajax/ other
var Foo = JSON.parse(data);
console.log("number: " + Foo.number);
console.log("title: " + Foo.title);
This is an interesting question, it is very easy using the new go versions. You should do this:
package main
import (
"fmt"
"encoding/json"
)
type User struct {
Name string `json:"name"`
}
func main() {
user := &User{name:"Frank"}
b, err := json.Marshal(user)
if err != nil {
fmt.Printf("Error: %s", err)
return;
}
fmt.Println(string(b))
}
Change this name to Name.
You can define your own custom MarshalJSON and UnmarshalJSON methods and intentionally control what should be included, ex:
package main
import (
"fmt"
"encoding/json"
)
type User struct {
name string
}
func (u *User) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
Name string `json:"name"`
}{
Name: "customized" + u.name,
})
}
func main() {
user := &User{name: "Frank"}
b, err := json.Marshal(user)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(b))
}
Struct values encode as JSON objects. Each exported struct field becomes
a member of the object unless:
the field's tag is "-", or
the field is empty and its tag specifies the "omitempty" option.
The empty values are false, 0, any nil pointer or interface value, and any array, slice, map, or string of length zero. The object's default key string is the struct field name but can be specified in the struct field's tag value. The "json" key in the struct field's tag value is the key name, followed by an optional comma and options.