I am sending the data to the API like following:
{"after": {"amount": 811,"id":123,"status":"Hi"}, "key": [70]}
and i am getting following while printing :
map[after:map[amount:811 id:123 status:Hi ] key:[70]]
Is there any way to print individual field like this??
amount::800
id:123
status:Hi
The code:
package main
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
"strings"
)
var (
PORT = ":8080"
)
func main() {
fmt.Println("In Main")
http.HandleFunc("/", changedData)
http.ListenAndServe(PORT, nil)
}
type Data struct {
Id int64 `json:"id"`
Amount float64 `json:"amount"`
Status string `json:"status"`
}
type mark map[string]interface{}
func changedData(w http.ResponseWriter, r *http.Request) {
fmt.Println("Coming From API")
reqBody, _ := ioutil.ReadAll(r.Body)
fmt.Println("Data coming from API ", string(reqBody))
digit := json.NewDecoder(strings.NewReader(string(reqBody)))
for digit.More() {
var result mark
err := digit.Decode(&result)
if err != nil {
if err != io.EOF {
log.Fatal(err)
}
break
}
fmt.Println("final_data ", result)
}
}
Decode to a Go type that matches the structure of the JSON document. You declared a type for the "after" field. Wrap that type with a struct to match the document.
func changedData(w http.ResponseWriter, r *http.Request) {
var v struct{ After Data }
err := json.NewDecoder(r.Body).Decode(&v)
if err != nil {
http.Error(w, "bad request", 400)
return
}
fmt.Printf("final_data: %#v", v.After)
}
Playground example.
I think you can define a struct type if you know the JSON file format or if the JSON format is predefined. As far as I know that mostly using interface{} is a way when you don't know the JSON format or there is no predefined format of the JSON. If you define a struct type and use it while unmarshaling the JSON to struct, you can access the variables by typing like data.Id or data.Status.
Here's an example code:
package main
import (
"encoding/json"
"fmt"
)
type Data struct {
AfterData After `json:"after"`
Key []int `json:"key"`
}
type After struct {
Id int64 `json:"id"`
Amount float64 `json:"amount"`
Status string `json:"status"`
}
func main() {
j := []byte(`{"after": {"amount": 811,"id":123,"status":"Hi"}, "key": [70]}`)
var data *Data
err := json.Unmarshal(j, &data)
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println(data.AfterData)
fmt.Println(data.AfterData.Id)
fmt.Println(data.AfterData.Amount)
fmt.Println(data.AfterData.Status)
}
Output will be
{123 811 Hi}
123
811
Hi
Go Playground
Related
In the below program I'm extracting some data from an API.
It outputs a rather complex data.
When I ioutil.ReadAll(resp.Body), the result is of type []uint8.
If I try to read the results, its just a random array of integers.
However, I'm able to read it if I convert it to string using string(diskinfo)
But I want to use this in a Struct and having trouble unmarshalling.
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"reflect"
)
type ApiResults struct {
results []struct {
statement_id int `json.statement_id`
series []struct {
name string `json.name`
tags struct {
host string `json.host`
}
columns []string `json.columns`
values []interface{} `json.values`
}
}
}
func main() {
my_url := "my_url"
my_qry := fmt.Sprintf("my_query")
resp, err := http.Get(my_url + url.QueryEscape(my_qry))
if err != nil {
fmt.Printf("ERROR: %v\n", err)
} else {
fmt.Println(reflect.TypeOf(resp))
diskinfo, _ := ioutil.ReadAll(resp.Body)
fmt.Println(reflect.TypeOf((diskinfo)))
fmt.Println(diskinfo)
fmt.Println(string(diskinfo))
diskinfo_string := string(diskinfo)
data := ApiResults{}
json.Unmarshal([]byte(diskinfo_string), &data)
//fmt.Printf("Values = %v\n", data.results.series.values)
//fmt.Printf("Server = %v\n", data.results.series.tags.host)
}
}
If I view the data as a string, I get this (formatted):
{"results":[
{"statement_id":0,
"series":[
{"name":"disk",
"tags":{"host":"myServer1"},
"columns":["time","disk_size"],
"values":[["2021-07-07T07:53:32.291490387Z",1044]]},
{"name":"disk",
"tags":{"host":"myServer2"},
"columns":["time","disk_size"],
"values":[["2021-07-07T07:53:32.291490387Z",1046]]}
]}
]}
I think my Apireturn struct is also structured incorrectly because the API results have info for multiple hosts.
But first, I doubt if the data has to be sent in a different format to the struct. Once I do this, I can probably try to figure out how to read from the Struct next.
The ioutil.ReadAll already provides you the data in the type byte[]. Therefore you can just call json.Unmarshal passing it as a parameter.
import (
"encoding/json"
"io/ioutil"
"net/http"
)
func toStruct(res *http.Response) (*ApiResults, error) {
body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, err
}
defer res.Body.Close()
data := ApiResults{}
if err := json.Unmarshal(body, &data); err != nil {
return nil, err
}
return data, nil
}
There also seems to be an issue with your struct. The correct way to use struct tags is as follows. Plus, fields need to be exported for the json tag (used by json.Umarshal) to work – starting with uppercase will do it.
type ApiResults struct {
Results []struct {
StatementId int `json:"statement_id"`
Series []struct {
Name string `json:"name"`
Tags struct {
Host string `json:"host"`
} `json:"tags"`
Columns []string `json:"columns"`
Values []interface{} `json:"values"`
} `json:"series"`
} `json:"results"`
}
I have a struct that I want to embed but want to json encode only certain fields of that struct (and lowercase them). Is that possible?
https://play.golang.org/p/bEC4zlx2oC:
package main
import (
"encoding/json"
"fmt"
"net/url"
)
type MyStruct struct {
Name string `json:"name"`
*url.URL
}
func main() {
m := &MyStruct{
"Bob",
&url.URL{
Scheme: "http",
},
}
j, err := json.Marshal(m)
if err != nil {
fmt.Println(err)
}
fmt.Println(string(j)) // want {"name":"Bob","scheme":"http"}
}
Expanding my comment with example.
It is feasible, you have to implement Marshal interface.
For example:
func (u *MyStruct) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
Name string `json:"name"`
Scheme string `json:"scheme"`
}{
Name: u.Name,
Scheme: u.Scheme,
})
}
Play Link: https://play.golang.org/p/LLchuOdYvf
Output:
{"name":"Bob","scheme":"http"}
I'm trying to decode a json I get. Here's an example json I get:
{"response":"1","number":"1234","id":nil}
Here's my struct:
type AutoGenerated struct {
Response string `json:"response"`
Number string `json:"number"`
ID interface{} `json:"id"`
}
I use the decode function in encode/json. What Am I getting wrong? ID has the chance to be both a string or a nil value.
Here's me exact error incase it helps.
panic: EOF
Without you showing how you're doing it, I think the best answer is to show you how to do it.
package main
import (
"fmt"
"log"
"encoding/json"
)
func main() {
j := []byte(`{"response":"1","number":"1234","id":null}`)
data := AutoGenerated{}
err := json.Unmarshal(j, &data)
if err != nil {
log.Println(err.Error())
return
}
fmt.Println(data)
}
type AutoGenerated struct {
Response string `json:"response"`
Number string `json:"number"`
ID interface{} `json:"id"`
}
The JSON string you put here is invalid. You can find this code sample for reference.
If you're going to set the id field to nil, just don't put it in the JSON string.
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"strings"
)
type AutoGenerated struct {
Response string `json:"response"`
Number string `json:"number"`
ID interface{} `json:"id"`
}
func main() {
jsonStream := `
{ "response": "1", "number": "1234" }
{ "response": "1", "number": "1234", "id": "nil" }
`
decoder := json.NewDecoder(strings.NewReader(jsonStream))
for {
var m AutoGenerated
if err := decoder.Decode(&m); err == io.EOF {
break
} else if err != nil {
log.Fatal(err)
}
fmt.Println(m)
}
}
The output of the program is:
{1 1234 <nil>}
{1 1234 nil}
I have an input of type strings.Reader. Given the input, I am extracting the id from it and printing it out. I then pass the original input to a generic function that perform other tasks on it. The only way I can think of reusing the original is to read the content and pass it to a bytes.Reader twice.
Is the following the only way to achieve that in Go?
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"strings"
)
type Food struct {
Id int `json:"id"`
Name string `json:"name"`
}
func genericFunction(body io.Reader) {
content, err := ioutil.ReadAll(body)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(content))
}
func main() {
// Original input
reader := strings.NewReader("{\"id\": 10, \"name\": \"Pie\"}")
original, err := ioutil.ReadAll(reader)
if err != nil {
log.Fatal(err)
}
foodReader := bytes.NewReader(original)
decoder := json.NewDecoder(foodReader)
var food Food
decoder.Decode(&food)
fmt.Println("About to eat food", food.Id)
foodReader = bytes.NewReader(original)
genericFunction(foodReader)
}
You can seek back to the start of the string with either the strings.Reader or bytes.Reader
reader := bytes.NewReader([]byte("{\"id\": 10, \"name\": \"Pie\"}"))
decoder := json.NewDecoder(reader)
var food Food
decoder.Decode(&food)
fmt.Println("About to eat food", food.Id)
reader.Seek(0, 0)
genericFunction(reader)
I'm trying to marshal a struct into json. It works when the struct has values. However, I'm unable to access the webpage when the struct has no value:
Go:
type Fruits struct {
Apple []*Description 'json:"apple, omitempty"'
}
type Description struct {
Color string
Weight int
}
func Handler(w http.ResponseWriter, r *http.Request) {
j := {[]}
js, _ := json.Marshal(j)
w.Write(js)
}
Is the error because json.Marshal cannot marshal an empty struct?
See here: http://play.golang.org/p/k6d6y7TnIQ
package main
import "fmt"
import "encoding/json"
type Fruits struct {
Apple []*Description `json:"apple, omitempty"`
}
type Description struct {
Color string
Weight int
}
func main() {
j := Fruits{[]*Description{}} // This is the syntax for creating an empty Fruits
// OR: var j Fruits
js, err := json.Marshal(j)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(js))
}