json.Decode doesn't decode numbers [duplicate] - json

This question already has an answer here:
json.Unmarshal returning blank structure
(1 answer)
Closed 2 years ago.
I basically copypasted this code from the documentation of the json package. In the provided example, the values of the JSON objects are strings. Here, I tried using integers instead.
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"strings"
)
func main() {
const jsonStream = `{"serverTime":35678}`
type Message struct {
serverTime int
}
dec := json.NewDecoder(strings.NewReader(jsonStream))
for {
var m Message
if err := dec.Decode(&m); err == io.EOF {
break
} else if err != nil {
log.Fatal(err)
}
fmt.Printf("its %v o clock\n", m.serverTime)
}
}
m.ServerTime should now be 35678, however, it's just 0. What am I doing wrong?

as document describes
The json package only accesses the exported fields of struct types (those that begin with an uppercase letter). Therefore only the the exported fields of a struct will be present in the JSON output.
so change serverTime to ServerTime, and add json tags json:"serverTime"
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"strings"
)
func main() {
const jsonStream = `{"serverTime":35678}`
type Message struct {
ServerTime int `json:"serverTime"`
}
dec := json.NewDecoder(strings.NewReader(jsonStream))
for {
var m Message
if err := dec.Decode(&m); err == io.EOF {
break
} else if err != nil {
log.Fatal(err)
}
fmt.Printf("its %v o clock\n", m.ServerTime)
}
}

Related

How to convert a time to UTC before marshaling as JSON in Go?

I'm trying to define a Time struct which implements the Marshaler interface such that, when it is marshaled to JSON, it is represented in the format YYYY-mm-ddTHH:MM:SSZ, that is, the time is converted to UTC and rounded to the nearest second. I've tried the following program:
package main
import (
"encoding/json"
"fmt"
"log"
"time"
)
type Time struct {
time.Time
}
func (t *Time) MarshalJSON() ([]byte, error) {
return []byte(t.Time.UTC().Round(time.Second).Format(time.RFC3339)), nil
}
func main() {
tm := time.Now()
// tm := time.Now().UTC().Round(time.Second)
tmJSON, err := json.Marshal(tm)
if err != nil {
log.Fatalf("marshal time: %v", err)
}
fmt.Println(string(tmJSON))
}
When I run this, however, it prints
> go run main.go
"2022-12-07T16:32:51.494597-08:00"
If, by contrast, I pass in time.Now().UTC().Round(time.Second) as the input to be marshaled (i.e., use the commented-out line in the snippet above), I get the desired output:
> go run main.go
"2022-12-08T00:41:10Z"
My question is: why can't I perform the conversion to UTC and rounding to the nearest second in the MarshalJSON method itself?
what are you trying to do?
I tried running your MarshalJSON function and it works as expected
here is what I tried to do:
package main
import (
"encoding/json"
"fmt"
"log"
"time"
)
type Time struct {
time.Time
}
func (t *Time) MarshalJSON() ([]byte, error) {
return []byte(t.Time.UTC().Round(time.Second).Format(time.RFC3339)), nil
}
func main() {
// tm := time.Now().UTC()
tm := time.Now().UTC().Round(time.Second)
tmJSON, err := json.Marshal(tm)
if err != nil {
log.Fatalf("marshal time: %v", err)
}
fmt.Println(string(tmJSON))
marshal_time := Time{time.Now().UTC()}
byt_arr, _ := marshal_time.MarshalJSON()
fmt.Println(string(byt_arr))
}
and i got the following output:
"2022-12-08T04:41:59Z"
2022-12-08T04:41:59Z
The first line is your previous output and the second output is of your MarshalJSON function.
You can use AppendFormat to convert your time string into buffer.
Also in your question you are not initialising your Time struct for Marshalling.
Here is a probable solution
package main
import (
"encoding/json"
"errors"
"fmt"
"log"
"time"
)
type Time struct {
time.Time
}
func (t *Time) MarshalJSON() ([]byte, error) {
if y := t.Year(); y < 0 || y >= 10000 {
return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")
}
b := make([]byte, 0, len(time.RFC3339)+2)
b = append(b, '"')
b = t.UTC().Round(time.Second).AppendFormat(b, time.RFC3339)
b = append(b, '"')
return b, nil
}
func main() {
now := time.Now()
mt := &Time{now}
bytArr, err := json.Marshal(mt)
if err != nil {
log.Fatalf("marshal time: %v", err)
}
fmt.Println(string(bytArr))
}

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

Trying to marshal a csv string to a struct

Here is my program :
package main
import (
"fmt"
"log"
"github.com/gocarina/gocsv"
)
// GeoAdresseCsv is a test structcd
type GeoAdresseCsv struct {
ID int `csv:"id"`
IDBan string `csv:"id_ban"`
}
func main() {
var adresseDB []GeoAdresseCsv
stringCsv := `id;id_ban
2908743;28009_0019_00008`
err := gocsv.UnmarshalString(stringCsv, &adresseDB)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", adresseDB)
}
But the ouput that i get is :
[{ID:0 IDBan:}]
How should i do correctly to get my csv string correctly mapped to my struct ?
While the separator in your data is ;, the package by default seems to use ,.
So we need to configure the package to use a different separator. According to the documentation, this is possible with a customizable CSV reader:
gocsv.SetCSVReader(func(in io.Reader) gocsv.CSVReader {
r := csv.NewReader(in)
r.Comma = ';' // This is our separator now
return r
})
This configures all functions in the package.
Your code should look like this to include the change:
package main
import (
"encoding/csv"
"fmt"
"io"
"log"
"github.com/gocarina/gocsv"
)
// GeoAdresseCsv is a test structcd
type GeoAdresseCsv struct {
ID int `csv:"id"`
IDBan string `csv:"id_ban"`
}
func main() {
gocsv.SetCSVReader(func(in io.Reader) gocsv.CSVReader {
r := csv.NewReader(in)
r.Comma = ';' // This is our separator now
return r
})
var adresseDB []GeoAdresseCsv
stringCsv := `id;id_ban
2908743;28009_0019_00008`
err := gocsv.UnmarshalString(stringCsv, &adresseDB)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", adresseDB)
}
Now the output is the expected value:
[{ID:2908743 IDBan:28009_0019_00008}]
You can run it online here.

Can get value of JSON in Go

I'm new in Go. I'm trying to read a JSON file and get a part of it for then operate with the values obtained.
My JSON is in the file example.json:
{"results":[{"statement_id":0,"series":[{"name":"cpu/node_utilization","columns":["time","distinct"],"values":[[10,1],[11,3],[13,5]]}]}]}
So what I would like to get is the "values" for get the sum of all the elements. In this case: 1+3+5
Here is the code that I have. I'm available to get the results, but then I don't manage to get series.
Here is the code that I have:
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
)
func main() {
// Open our jsonFile
jsonFile, err := os.Open("example.json")
// if we os.Open returns an error then handle it
if err != nil {
fmt.Println(err)
}
fmt.Println("Successfully Opened example.json")
// defer the closing of our jsonFile so that we can parse it later on
defer jsonFile.Close()
byteValue, _ := ioutil.ReadAll(jsonFile)
var all_data map[string]interface{}
json.Unmarshal([]byte(byteValue), &all_data)
fmt.Println(all_data["results"])
}
I've tried diferent solutions like
all_data["results"].(map[string]interface{})["series"])
But the problem is that the map is in an array, and I don't know how to solve it.
Using interfaces and map
package main
import (
"encoding/json"
"fmt"
)
func main() {
byteValue := []byte(`{"results":[{"statement_id":0,"series":[{"name":"cpu/node_utilization","columns":["time","distinct"],"values":[[10,1],[11,3],[13,5]]}]}]}`)
var all_data map[string][]interface{}
json.Unmarshal([]byte(byteValue), &all_data)
fmt.Println("result:", all_data["results"])
for _, r := range all_data["results"] {
s := r.(map[string]interface{})
fmt.Println("series:", s["series"])
w := s["series"].([]interface{})
for _, x := range w {
y := x.(map[string]interface{})
fmt.Println(y)
z := y["values"].([]interface{})
fmt.Println("values:", z)
for _, v := range z {
u := v.([]interface{})
fmt.Println(u)
for _, i := range u {
val := i.(float64)
fmt.Println(val)
}
}
}
}
}
I have solved defining an Struct.
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
)
type AutoGenerated struct {
Results []struct {
StatementID int `json:"statement_id"`
Series []struct {
Name string `json:"name"`
Columns []string `json:"columns"`
Values [][]int `json:"values"`
} `json:"series"`
} `json:"results"`
}
func main() {
// Open our jsonFile
jsonFile, err := os.Open("example.json")
// if we os.Open returns an error then handle it
if err != nil {
fmt.Println(err)
}
fmt.Println("Successfully Opened example.json")
// defer the closing of our jsonFile so that we can parse it later on
defer jsonFile.Close()
byteValue, _ := ioutil.ReadAll(jsonFile)
all_data := AutoGenerated{}
json.Unmarshal([]byte(byteValue), &all_data)
fmt.Println(all_data.Results[0].Series[0].Values)
}
I have used this web to generate automatically the Struct providing the JSON structure

How to use switch in GO with json keys?

Here is an example of POST request body:
{"action":"do_something","id":"001"}
I took an example of simple json parser
package main
import (
"encoding/json"
"fmt"
"net/http"
)
type some_json struct {
Action string `json:"action"`
Id string `json:"id"`
}
func jsonparse(rw http.ResponseWriter, request *http.Request) {
decoder := json.NewDecoder(request.Body)
var post_data some_json
err := decoder.Decode(&post_data)
if err != nil {
panic(err)
}
switch ***WHAT_SHOULD_BE_HERE???*** {
default :
fmt.Fprintf(w,"WRONG PARAM")
case "some_thing":
fmt.Fprintf(w,post_data.Id + "\n\n")
}
}
func main() {
http.HandleFunc("/", jsonparse)
http.ListenAndServe(":8080", nil)
}
I already know how to switch cases from form values, but
how to switch cases of json key values?
I am not sure what you want to switch, but i think that you just need to erase the () so Action is not a function call anymore
Be careful maybe your error is that u mixed up the strings
in JSON: "do_something"
in case: "some_thing"
You can copy following code to playground
package main
import (
"encoding/json"
"fmt"
"strings"
)
type some_json struct {
Action string `json:"action"`
Id string `json:"id"`
}
func jsonparse() {
r := strings.NewReader("{\"action\":\"do_something\",\"id\":\"001\"}")
decoder := json.NewDecoder(r)
var post_data some_json
err := decoder.Decode(&post_data)
if err != nil {
panic(err)
}
switch post_data.Action {
default:
fmt.Println( "WRONG PARAM")
case "do_something":
fmt.Println( post_data.Id+"\n\n")
}
}
func main() {
jsonparse()
}