Use string as struct value - go

I have this code. What I need is to get the transaction details from the transaction ID returned from blockchain
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
)
type Transaction struct {
Bid string `json:"bid"`
Fun string `json:"fun"`
ID string `json:"id"`
Timestamp string `json:"timestamp"`
TraderA string `json:"traderA"`
TraderB string `json:"traderB"`
Seller string `json:"seller"`
PointAmount string `json:"pointAmount"`
PrevTransactionID string `json:"prevTransactionId"`
}
type AllTxs struct {
TXs []Transaction `json:"tx"`
}
type Transact struct {
Cert string `json:"cert"`
ChaincodeID string `json:"chaincodeID"`
Nonce string `json:"nonce"`
Payload string `json:"payload"`
Signature string `json:"signature"`
Timestamp string `json:"nanos"`
Txid string `json:"txid"`
Type int `json:"type"`
}
func main() {
resp, err := http.Get("http://blockchain_transactions_url/trans_id")
if err != nil {
// handle error
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
byteArray := []byte(body)
var t Transact
json.Unmarshal(byteArray, &t)
//I get all the values base64 encoded
st, err := base64.StdEncoding.DecodeString(t.Payload)
if err != nil {
log.Fatal(err)
}
trd := string(st)
sp := strings.Split(trd, "\n")
result := strings.Join(sp, ",")
res := strings.Replace(result, ",", `", "`, -1)
ret := strings.Replace(res, `", "`, `{"`, 1) + `"}`
byteA := []byte(ret)
var tf AllTxs
json.Unmarshal(byteA, &tf)
//the tf...
ref := Transaction{}
fmt.Println(ref.Id)
}
the t.Payload I get is
"CsYBCAESgwESgAE3ZjFhY2Y2MTgxMGRhODMyMTA5NjZiNGYzNjc2NWU5NmIxY2Q0OTliODkyNmY0MDU0YWQ5NzhlNzhkZjczMDRhOGZlMDM1ZjZhYTBhODE2YzdmNjFlNGZkZDQ1MjM4M2Q5ZmU5ZDQxNmIyZGI4YTE1YmRkMjAzZmU2N2I5OTYyZho8ChBpbml0X3RyYW5zYWN0aW9uCgYwMDAxMTcKA2dpbwoEbW9oYQoBNQoCMTIKBTk4NzczCgcyMDE3NDIy"
the tf I get is
{"??7f1acf61810da83210966b4f36765e96b1cd499b8926f4054ad978e78df7304a8fe035f6aa0a816c7f61e4fdd452383d9fe9d416b2db8a15bdd203fe67b9962f<", "init_transaction", "000117", "gio", "moha", "5", "12", "98773", "2017422"}
At the last how can I get the JSON of Transaction/AllTxs type?

Given the comment, it looks like you are trying to unmarshal the string as JSON, but as it stands, the string is not valid JSON; if it were, you would be able to unmarshal it as follows, ignoring the fact that the fields to not appear to match up with the desired structure;
package main
import (
"encoding/json"
"fmt"
)
type Transaction struct {
Bin string `json:"bin"`
Fun string `json:"fun"`
ID string `json:"id"`
Timestamp string `json:"timestamp"`
TraderA string `json:"traderA"`
TraderB string `json:"traderB"`
Seller string `json:"seller"`
PointAmount string `json:"pointAmount"`
PrevTransactionID string `json:"prevTransactionId"`
}
func main() {
snippet := `{
"bin": "7f1acf61810da83210966b4f36765e96b1cd499b8926f4054ad978e78df7304a8fe035f6aa0a816c7f61e4fdd452383d9fe9d416b2db8a15bdd203fe67b9962f",
"fun": "init_transaction",
"id": "000117",
"timestamp": "gio",
"traderA": "moha",
"traderB": "5",
"seller": "12",
"pointAmount": "98773",
"prevTransactionId": "2017422"
}`
t := Transaction{}
json.Unmarshal([]byte(snippet), &t)
fmt.Println(t)
}

Related

How to extract data from map[string]interface{}?

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

Extracting Data From Kafka REST Proxy in Go

I am using the REST proxy instance of Kafka for producing and consuming messages.Using the API to get new messages but I am not able to convert those messages to a struct model in Go. For example:
// Get records
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf(FETCH_CONSUMER, URL, GROUP, CONSUMER), nil)
if err != nil {
panic(err)
}
req.Header.Add("Accept", CONTENT_TYPE)
respRecords, err := client.Do(req)
if err != nil {
panic(err)
}
defer respRecords.Body.Close()
fmt.Printf("Response %s\n", respRecords.Status)
fmt.Println(respRecords.Body)
recordsBodyResp := bufio.NewScanner(respRecords.Body)
for recordsBodyResp.Scan() {
fmt.Printf("<--Body %s\n", recordsBodyResp.Text())
}
The value returned is in the following format:
[{"topic":"backward","key":null,"value":{"AdoptionID":"abcd123","IPAddress":"8.8.8.8","Port":"80","Status":"requested"},"partition":0,"offset":7}]
Since it's an array of objects, I want to extract the value portion of the key "value" into a struct.
That is where I am stuck.
You can create a struct like:
type AutoGenerated []struct {
Topic string `json:"topic"`
Key interface{} `json:"key"`
Value Value `json:"value"`
Partition int `json:"partition"`
Offset int `json:"offset"`
}
type Value struct {
AdoptionID string `json:"AdoptionID"`
IPAddress string `json:"IPAddress"`
Port string `json:"Port"`
Status string `json:"Status"`
}
And Unmarshal in that struct.
See this sample code:
package main
import (
"fmt"
"encoding/json"
)
func main() {
type Value struct {
AdoptionID string `json:"AdoptionID"`
IPAddress string `json:"IPAddress"`
Port string `json:"Port"`
Status string `json:"Status"`
}
type AutoGenerated []struct {
Topic string `json:"topic"`
Key interface{} `json:"key"`
Value Value `json:"value"`
Partition int `json:"partition"`
Offset int `json:"offset"`
}
byt := []byte(`[{"topic":"backward","key":null,"value":{"AdoptionID":"abcd123","IPAddress":"8.8.8.8","Port":"80","Status":"requested"},"partition":0,"offset":7}]`)
var dat AutoGenerated
if err := json.Unmarshal(byt, &dat); err != nil {
panic(err)
}
fmt.Printf("%#v", dat)
}

Reading and Unmarshalling API results in Golang

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"`
}

Marshall/Unmarshal JSONPB

I am trying to Unmarshal some json data to a proto message.
JSON
{
"id": 1,
"first_name": "name",
"phone_numbers": []
}
Proto
message Item {
uint32 id=1;
string name=2;
repeated string numbers=3;
}
Proto.go
type Item struct {
Id uint32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"`
Numbers []string `protobuf:"bytes,4,rep,name=numbers" json:"numbers,omitempty"`
}
How can I map the above JSON to my proto Message (from what I can see there is no way to specify tags in proto atm)?
Your JSON document doesn't match the proto definition; name != first_name and numbers != phone_numbers.
You can define another type that has the same fields as Item but different struct tags and then convert to Item:
var x struct {
Id uint32 `json:"id,omitempty"`
Name string `json:"first_name,omitempty"`
Numbers []string `json:"phone_numbers,omitempty"`
}
if err := json.Unmarshal(jsonDoc, &x); err != nil {
log.Fatal(err)
}
var i = Item(x)
If every JSON document you want to decode has this structure, it may be more convenient to let Item implement json.Unmarshaler:
package main
import (
"encoding/json"
"fmt"
"log"
)
var jsonDoc = []byte(`
{
"id": 1,
"first_name": "name",
"phone_numbers": [
"555"
]
}
`)
type Item struct {
Id uint32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"`
Numbers []string `protobuf:"bytes,4,rep,name=numbers" json:"numbers,omitempty"`
}
// You can define this function is item_json.go or so, then it
// isn't removed if you re-generate your types.
func (i *Item) UnmarshalJSON(b []byte) error {
type item struct {
Id uint32 `json:"id,omitempty"`
Name string `json:"first_name,omitempty"`
Numbers []string `json:"phone_numbers,omitempty"`
}
var x item
if err := json.Unmarshal(jsonDoc, &x); err != nil {
return err
}
*i = Item(x)
return nil
}
func main() {
var i Item
if err := json.Unmarshal(jsonDoc, &i); err != nil {
log.Fatal(err)
}
fmt.Printf("%#v\n", i)
}
Try it on the playground: https://play.golang.org/p/0qibavRJbwi

Recieving a EOF Panic error

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}

Resources