How to serialize a dictionary in golang - json

I try to replicate this body form in order to use it in a request:
{"Responses":[{"type":"DROP_DOWN","value":"0"}]}
so what im doing is :
type FruitBasket struct {
Name5 []string `json:"Responses"`
}
form := payload{
Name5: []string{"type", "value"},
}
jsonData, err := json.Marshal(form)
fmt.Println(string(jsonData))
But i can't find a way to complete the body in the brackets

You need to use the Unmarshal function from "encoding/json" package and use a dummy struct to extract the slice fields
// You can edit this code!
// Click here and start typing.
package main
import (
"encoding/json"
"fmt"
)
func main() {
str := `{"Responses":[{"type":"DROP_DOWN","value":"0"}]}`
type Responses struct {
Type string `json:"type"`
Value string `json:"value"`
}
// add dummy struct to hold responses
type Dummy struct {
Responses []Responses `json:"Responses"`
}
var res Dummy
err := json.Unmarshal([]byte(str), &res)
if err != nil {
panic(err)
}
fmt.Println("%v", len(res.Responses))
fmt.Println("%s", res.Responses[0].Type)
fmt.Println("%s", res.Responses[0].Value)
}

JSON-to-go is a good online resource to craft Go date types for a particular JSON schema.
Pasting your JSON body & extracting out the nested types you could use the following types to generate the desired JSON schema:
// types to produce JSON:
//
// {"Responses":[{"type":"DROP_DOWN","value":"0"}]}
type FruitBasket struct {
Response []Attr `json:"Responses"`
}
type Attr struct {
Type string `json:"type"`
Value string `json:"value"`
}
to use:
form := FruitBasket{
Response: []Attr{
{
Type: "DROP_DOWN",
Value: "0",
},
}
}
jsonData, err := json.Marshal(form)
working example: https://go.dev/play/p/SSWqnyVtVhF
output:
{"Responses":[{"type":"DROP_DOWN","value":"0"}]}

Your struct is not correct. Your title want dictionary, but you write an array or slice of string.
Change your FruitBasket struct from this:
type FruitBasket struct {
Name5 []string `json:"Responses"`
}
to this
type FruitBasket struct {
Name5 []map[string]interface{} `json:"Responses"`
}
map[string]interface{} is dictionary in go
here's the playground https://go.dev/play/p/xRSDGdZYfRN

Related

hh:mm:ss to time.Time while parsing from JSON in Go

I have a struct that I can't change and an array of these structs in a separate JSON file.
I could have parsed data from JSON file easily, but there are mismatched types in same fields:
(main.go)
import "time"
type SomeType struct {
name string `json: "name"`
time time.Time `json: "someTime"`
}
(someData.json)
[
{
"name": "some name",
"someTime": "15:20:00"
},
{
"name": "some other name",
"someTime": "23:15:00"
}
]
If "time" field was a type of a string, I would simply use json.Unmarshal and parse all of the data from json into []SomeType, but since types mismatch, I can't find a way to do it correctly.
You should add the UnmarshalJSON method to your struct
type SomeType struct {
Name string `json:"name"`
Time time.Time `json:"someTime"`
}
func (st *SomeType) UnmarshalJSON(data []byte) error {
type parseType struct {
Name string `json:"name"`
Time string `json:"someTime"`
}
var res parseType
if err := json.Unmarshal(data, &res); err != nil {
return err
}
parsed, err := time.Parse("15:04:05", res.Time)
if err != nil {
return err
}
now := time.Now()
st.Name = res.Name
st.Time = time.Date(now.Year(), now.Month(), now.Day(), parsed.Hour(), parsed.Minute(), parsed.Second(), 0, now.Location())
return nil
}
GoPlay
I think you should define a custom time type, with a custom unmarshaller as follows:
type CustomTime struct {
time.Time
}
func (t *CustomTime) UnmarshalJSON(b []byte) error {
formattedTime, err := time.Parse(`"15:04:05"`, string(b))
t.Time = formattedTime
return err
}
And have another struct, which is basically the exact struct you have, instead it uses your custom time type rather than the original struct which uses time.Time:
type SameTypeWithDifferentTime struct {
Name string `json:"name"`
SomeTime CustomTime `json:"someTime"`
}
func (s SameTypeWithDifferentTime) ToOriginal() SomeType {
return SomeType {
Name: s.Name,
SomeTime: s.SomeTime.Time,
}
}
The rest of the process is pretty straight forward, you just deserialize your json to the new type, and use ToOriginal() receiver function to convert it to your original struct. Another point to mention here is that your not exporting your struct fields.

Parsing dynamic json in go

I am trying to parse the following json structure, where the fields marked with "val1" and "val2" are constantly changing, so I cannot use a predefined struct. How could I parse this json in a way to be able to loop through every single "val"? Thank you!
{"result":true,"info":{"funds":{"borrow":{"val1":"0","val2":"0"},"free":{"val1":"0","val2":"0"},"freezed":{"val1":"0","val2":"0"}}}}
By unmarshalling into the following struct I can loop through the desired fields.
type Fields struct {
Result bool `json:"result"`
Info struct {
Funds struct {
Borrow, Free, Freezed map[string]interface{}
} `json:"funds"`
} `json:"info"`
}
package main
import (
"fmt"
"encoding/json"
)
type Root struct {
Result bool `json:"result"`
Info Info `json:"info"`
}
type Info struct {
Funds struct {
Borrow, Free, Freezed map[string]interface{}
} `json:"funds"`
}
func main() {
var rootObject Root
jsonContent := " {\"result\":true,\"info\":{\"funds\":{\"borrow\":{\"val1\":\"0\",\"val2\":\"0\"},\"free\":{\"val1\":\"0\",\"val2\":\"0\"},\"freezed\":{\"val1\":\"0\",\"val2\":\"0\"}}}}"
if err := json.Unmarshal([]byte(jsonContent), &rootObject); err != nil {
panic(err)
}
fmt.Println(rootObject)
}

Why doesn't JSON parsing fail with completely different type passed to Decode()?

I have the following data structures which I'd like to parse from an API:
type OrderBook struct {
Pair string `json:"pair"`
UpdateTime int64 `json:"update_time"`
}
type depthResponse struct {
Result OrderBook `json:"result"`
// doesn't matter here
//Cmd string `json:"-"`
}
and when I parse the following:
data := `{"error":{"code":"3016","msg":"交易对错误"},"cmd":"depth"}`
It doesn't fail. Why?
Full source code (playground)
package main
import (
"encoding/json"
"fmt"
"log"
"strings"
)
type OrderBook struct {
Pair string `json:"pair"`
UpdateTime int64 `json:"update_time"`
}
type depthResponse struct {
Result OrderBook `json:"result"`
}
func main() {
data := `{"error":{"code":"3016","msg":"交易对错误"},"cmd":"depth"}`
r := strings.NewReader(data)
var resp depthResponse
if err := json.NewDecoder(r).Decode(&resp); err != nil {
log.Fatalf("We should end up here: %v", err)
}
fmt.Printf("%+v\n", resp)
}
That's the expected behaviour of Decode (as documented in the Unmarshal function):
https://golang.org/pkg/encoding/json/#Unmarshal
By default, object keys which don't have a corresponding struct field are ignored.
You can however use the DisallowUnknownFields() function (as described in the docs as well) to have it fail if the input JSON has fields not contained in the destination struct.
dec := json.NewDecoder(r)
dec.DisallowUnknownFields()
In that case, you'll get an error as you expect.
Modified playground here: https://play.golang.org/p/A0f6dxTXV34

Creating JSON representation from Go struct

I am trying to create a JSON string from a struct:
package main
import "fmt"
func main() {
type CommentResp struct {
Id string `json: "id"`
Name string `json: "name"`
}
stringa := CommentResp{
Id: "42",
Name: "Foo",
}
fmt.Println(stringa)
}
This code prints {42 foo}, but I expected {"Id":"42","Name":"Foo"}.
What you are printing is fmt's serialization of the CommentResp struct. Instead, you want to do is use json.Marshal to get the encoded JSON repsentation:
data, err := json.Marshal(stringa)
if err != nil {
// Problem encoding stringa
panic(err)
}
fmt.Println(string(data))
https://play.golang.org/p/ogWKQ3M6tb
Also, your json struct tags are not valid; there cannot be a space between : and the quoted string:
type CommentResp struct {
Id string `json:"id"`
Name string `json:"name"`
}
https://play.golang.org/p/eQiyTk6-vQ

golang json unmarshal part of map[string]interface{}

I have the following code to try to Unmarshal this json file, however the line json.Unmarshal([]byte(msg["restaurant"]), &restaurant) always gives an error. How can I make Unmarshal ignore the "restaurant" or pass only the "restaurant" data to the Unmarshal function?
Thanks!
{
"restaurant": {
"name": "Tickets",
"owner": {
"name": "Ferran"
}
}
}
file, e := ioutil.ReadFile("./rest_read.json")
if e != nil {
fmt.Println("file error")
os.Exit(1)
}
var data interface{}
json.Unmarshal(file, &data)
msg := data.(map[string]interface{})
log.Println(msg)
log.Println(msg["restaurant"])
log.Println(reflect.TypeOf(msg["restaurant"]))
var restaurant Restaurant
json.Unmarshal([]byte(msg["restaurant"]), &restaurant)
log.Println("RName: ", restaurant.Name)
log.Println("Name: ", restaurant.Owner.Name)
It is possible to do generic unmarshalling ala gson by decoding into an interface and then extracting a top level map from the result, e.g:
var msgMapTemplate interface{}
err := json.Unmarshal([]byte(t.ResponseBody), &msgMapTemplate)
t.AssertEqual(err, nil)
msgMap := msgMapTemplate.(map[string]interface{})
See "decoding arbitrary data" in http://blog.golang.org/json-and-go for more into.
I would propose to construct a proper model for your data. This will enable you to cleanly unmarshal your data into a Go struct.
package main
import (
"encoding/json"
"fmt"
)
type Restaurant struct {
Restaurant RestaurantData `json:"restaurant"`
}
type RestaurantData struct {
Name string `json:"name"`
Owner Owner `json:"owner"`
}
type Owner struct {
Name string `json:"name"`
}
func main() {
data := `{"restaurant":{"name":"Tickets","owner":{"name":"Ferran"}}}`
r := Restaurant{}
json.Unmarshal([]byte(data), &r)
fmt.Printf("%+v", r)
}
Unmarshalling occurs recursively, so msg["restaurant"] is no longer a json string - it is another map[string]interface{}. If you want to unmarshall directly into a Restaurant object, you will have to provide a simple wrapper object with a Restaurant member and unmarshall into that.