Parsing dynamic json in go - json

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)
}

Related

How to serialize a dictionary in golang

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

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

Golang unmarshal json that starts as an array

I'm trying to unmarshal this json https://www.reddit.com/r/videos/comments/3vgdsb/recruitment_2016.json
It starts as an array of two different objects, and I only need data on the second object.
I want to retrieve the comments body, it doesn't give me any error when i'm trying to decode it, but it doesn't capture the data I want.
This is the output I get from running this:
//Response struct when initialized: []
//Response struct decoded: [{{{[]}}} {{{[]}}}]
////
type Response []struct {
Parent struct {
Data struct {
Children []struct {
Com Comment
}
}
}
}
type Comment struct {
Name string `json:"body"`
}
func init() {
http.HandleFunc("/api/getcomments", getComments)
}
func getComments(w http.ResponseWriter, r *http.Request) {
url := "https://www.reddit.com/r/videos/comments/3vgdsb/recruitment_2016.json"
c := appengine.NewContext(r)
client := urlfetch.Client(c)
resp, err := client.Get(url)
if err != nil { fmt.Fprint(w, "Error client.Get(): ", err) }
re := new(Response)
fmt.Fprint(w, "Response struct: ", re, "\n")
errTwo := json.NewDecoder(resp.Body).Decode(&re)
if errTwo != nil { fmt.Fprint(w, "Error decoding: ", errTwo, "\n") }
fmt.Fprint(w, "Response struct: ", re)
}
For everyone that is struggling to create the right structure for JSON unmarshalling, here's a cool website that convert any JSON to the right Go struct: JSON-to-Go
The json data you are unmarshaling does not conform with your data, and if the names of the fields are not like in your struct, you should use struct tags as well. It should be more like this:
type Response []struct {
Kind string `json:"kind"`
Data struct {
Children []struct {
Data struct {
Replies []struct {
// whatever...
} `json:"replies"`
} `json:"data"`
} `json:"children"`
} `json:"data"`
}
}
Of course I'd replace the inline types with real, named types, but I'm just making a point here in regards to the data hierarchy.
Goddamn, that's some ugly bloated JSON BTW.

Unmarshal nested JSON structure

http://play.golang.org/p/f6ilWnWTjm
I am trying to decode the following string but only getting null values.
How do I decode nested JSON structure in Go?
I want to convert the following to map data structure.
package main
import (
"encoding/json"
"fmt"
)
func main() {
jStr := `
{
"AAA": {
"assdfdff": ["asdf"],
"fdsfa": ["1231", "123"]
}
}
`
type Container struct {
Key string `json:"AAA"`
}
var cont Container
json.Unmarshal([]byte(jStr), &cont)
fmt.Println(cont)
}
Use nested structs in Go to match the nested structure in JSON.
Here's one example of how to handle your example JSON:
package main
import (
"encoding/json"
"fmt"
"log"
)
func main() {
jStr := `
{
"AAA": {
"assdfdff": ["asdf"],
"fdsfa": ["1231", "123"]
}
}
`
type Inner struct {
Key2 []string `json:"assdfdff"`
Key3 []string `json:"fdsfa"`
}
type Container struct {
Key Inner `json:"AAA"`
}
var cont Container
if err := json.Unmarshal([]byte(jStr), &cont); err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", cont)
}
playground link
You can also use an anonymous type for the inner struct:
type Container struct {
Key struct {
Key2 []string `json:"assdfdff"`
Key3 []string `json:"fdsfa"`
} `json:"AAA"`
}
playground link
or both the outer and inner structs:
var cont struct {
Key struct {
Key2 []string `json:"assdfdff"`
Key3 []string `json:"fdsfa"`
} `json:"AAA"`
}
playground link
If you don't know the field names in the inner structure, then use a map:
type Container struct {
Key map[string][]string `json:"AAA"`
}
http://play.golang.org/p/gwugHlCPLK
There are more options. Hopefully this gets you on the right track.
First of all: Don't ignore errors returned by a function or method unless you have a very good reason to do so.
If you make the following change to the code:
err := json.Unmarshal([]byte(jStr), &cont)
if err != nil {
fmt.Println(err)
}
You will see the error message telling you why the value is empty:
json: cannot unmarshal object into Go value of type string
Simply put: Key cannot be of type string, so you have to use a different type. You have several option on how to decode it depending on the characteristics of the Key value:
If the structure is static, use another struct to match this structure.
If the structure is dynamic, use interface{} (or map[string]interface{} if it is always of type JSON object)
If the value is not to be accessed, only to be used in later JSON encoding, or if the decoding is to be delayed, use json.RawMessage

How do I unmarshal JSON into a Go struct provided by a different piece of code?

I am writing a Go library that will decode JSON into a struct. The JSON has a fairly simple common schema, but I want consumers of this library to be able to decode additional fields into their own structs that embed the common struct, avoiding the need to use maps. Ideally, I'd like to decode the JSON only once.
Currently it looks something like this. (Error handling removed for brevity.)
The JSON:
{ "CommonField": "foo",
"Url": "http://example.com",
"Name": "Wolf" }
The library code:
// The base JSON request.
type BaseRequest struct {
CommonField string
}
type AllocateFn func() interface{}
type HandlerFn func(interface{})
type Service struct {
allocator AllocateFn
handler HandlerFn
}
func (Service *s) someHandler(data []byte) {
v := s.allocator()
json.Unmarshal(data, &v)
s.handler(v)
}
The app code:
// The extended JSON request
type MyRequest struct {
BaseRequest
Url string
Name string
}
func allocator() interface{} {
return &MyRequest{}
}
func handler(v interface{}) {
fmt.Printf("%+v\n", v);
}
func main() {
s := &Service{allocator, handler}
// Run s, eventually s.someHandler() is called
}
The thing I don't like about this setup is the allocator function. All implementations are simply going to return a new BaseRequest "sub-type". In a more dynamic language I would pass the type of MyRequest in instead, and instantiate inside the library. Do I have a similar option in Go?
There are several ways to handle this. One idea which is both simple and convenient is defining a richer Request type that you provide to the handler, instead of handing off the raw type. This way you can implement the default behavior in a friendly way, and support the edge cases. This would also avoid the need to embed the default type on custom types, and allow you to expand functionality without breaking clients.
For inspiration:
type Request struct {
CommonField string
rawJSON []byte
}
func (r *Request) Unmarshal(value interface{}) error {
return json.Unmarshal(r.rawJSON, value)
}
func handler(req *Request) {
// Use common data.
fmt.Println(req.CommonField)
// If necessary, poke into the underlying message.
var myValue MyType
err := req.Unmarshal(&myValue)
// ...
}
func main() {
service := NewService(handler)
// ...
}
I think json.RawMessage is used to delay decoding subsets of JSON. In your case you can maybe do something like this:
package main
import (
↦ "encoding/json"
↦ "fmt"
)
type BaseRequest struct {
↦ CommonField string
↦ AppData json.RawMessage
}
type AppData struct {
↦ AppField string
}
var someJson string = `
{
↦ "CommonField": "foo",
↦ "AppData": {
↦ ↦ "AppField": "bar"
↦ }
}
`
func main() {
↦ var baseRequest BaseRequest
↦ if err := json.Unmarshal([]byte(someJson), &baseRequest); err != nil {
↦ ↦ panic(err)
↦ }
↦ fmt.Println("Parsed BaseRequest", baseRequest)
↦ var appData AppData
↦ if err := json.Unmarshal(baseRequest.AppData, &appData); err != nil {
↦ ↦ panic(err)
↦ }
↦ fmt.Println("Parsed AppData", appData)
}
Another way I came up with is to use reflection.
Tweaking my original example, the library code becomes:
// The base JSON request.
type BaseRequest struct {
CommonField string
}
type HandlerFn func(interface{})
type Service struct {
typ reflect.Type
handler HandlerFn
}
func (Service *s) someHandler(data []byte) {
v := reflect.New(s.typ).Interface()
json.Unmarshal(data, &v)
s.handler(v)
}
and the app code becomes:
// The extended JSON request
type MyRequest struct {
BaseRequest
Url string
Name string
}
func handler(v interface{}) {
fmt.Printf("%+v\n", v);
}
func main() {
s := &Service{reflect.TypeOf(MyRequest{}), handler}
// Run s, eventually s.someHandler() is called
}
I haven't decided if I like this any better. Maybe the way to go is just to simply unmarshal the data twice.