Unmarshal JSON to map[any]any - json

I want to unmarshal a JSON object to a map of map[any]any. This yields the error json: cannot unmarshal object into Go value of type map[interface {}]interface {}. Why is this not possible?
package main
import (
"encoding/json"
"fmt"
)
func main() {
bytes := []byte(`{"sendMsg":{"user":"ANisus","msg":"Trying to send a message"},"say":"Hello"}`)
var bytesInMap map[any]any
err := json.Unmarshal(bytes, &bytesInMap)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("Hello World %s", bytesInMap)
}

Related

json: cannot unmarshal string into Go value of type MyMap.map

I met problem with marshaling JSON in golang.
I need to unmarshal json object, that I recieve from UDP packets.
But I met problem with unmarshaling - it doesn't want to unmarshal properly.
I get "Error with unmarshaling: json: cannot unmarshal string into Go value of type main.MyMap" error.
I tested in different ways, but feel stuck on this example - marshaland unmarshal in one line, and still get errors.
package main
import (
"encoding/json"
"fmt"
"log"
)
type MyMap struct {
Param map[string]string `json:"packet"`
}
func main() {
rawJson := []byte(`{
"packet":{
"hostname":"host1",
"pid":"123435",
"processname":"process",
"type":"partial"}
}`)
data, err := json.Marshal(rawJson)
if err != nil {
log.Println("Error with marchal JSON: " + err.Error())
}
var unmarshaled MyMap
err = json.Unmarshal(data, &unmarshaled)
if err != nil {
fmt.Printf("Error with unmarshaling: %v", err)
return
}
fmt.Printf("Read a message from %v %s \n", unmarshaled.Param["pid"], unmarshaled.Param["processname"])
}
If I'm trying to unmarshal JSON, that I received from UDP, the error says
invalid character 'i/x01' looking for beginning of value
I believe I get this kind of error because of my misunderstanding of marshal system.
I'd be appreciate if you help me
Thanks!
you should change rawjson to string type and change your order code same as:
package main
import (
"encoding/json"
"fmt"
)
type MyMap struct {
Param map[string]string `json:"packet"`
}
func main() {
rawJson := `{
"packet":{
"hostname":"host1",
"pid":"123435",
"processname":"process",
"type":"partial"}
}`
struct_instance := MyMap{}
if er := json.Unmarshal([]byte(rawJson), &struct_instance); er != nil {
fmt.Println(er)
}
fmt.Println(struct_instance)
json_as_byte, er := json.Marshal(struct_instance)
if er != nil {
fmt.Println(er)
}
fmt.Println(string(json_as_byte))
}
I did few changes in your code and it's worked very well.
You can run it here: https://go.dev/play/p/jvw9MsVFbHt
type mp map[string]string
type MyMap struct {
Param mp `json:"packet"`
}
func main() {
rawJson := []byte(`{
"packet":{
"hostname":"host1",
"pid":"123435",
"processname":"process",
"type":"partial"}
}`)
data, err := json.Marshal(rawJson) //Not Required
if err != nil {
fmt.Println("Error with marchal JSON: " + err.Error())
}
fmt.Println("data ", data)
var res MyMap
json.Unmarshal(rawJson, &res)
fmt.Printf("Read a message from %v %s \n", res.Param["pid"], res.Param["processname"])
}

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

Cannot unmarshal object into Go value of type []uint8

I am fairly new to Go. I have the following code:
package main
import (
"encoding/json"
"fmt"
)
func main() {
byt := []byte(`{"num":6.13,"strs":["a","b"]}`)
dat := []byte(`{"num":7.13,"strs":["c","d"]}`)
if err := json.Unmarshal(byt, &dat); err != nil {
panic(err)
}
fmt.Println(dat)
}
Getting the error:
cannot "unmarshal object into Go value of type []uint8".
How can I fix this please?
You have 2 JSON inputs, and you're trying to unmarshal one into the other. That doesn't make any sense.
Model your JSON input (the object) with a type (struct), and unmarshal into that. For example:
type Obj struct {
Num float64 `json:"num"`
Strs []string `json:"strs"`
}
func main() {
byt := []byte(`{"num":6.13,"strs":["a","b"]}`)
var obj Obj
if err := json.Unmarshal(byt, &obj); err != nil {
panic(err)
}
fmt.Println(obj)
}
Output (try it on the Go Playground):
{6.13 [a b]}
I think you meant to do something like this:
package main
import (
"encoding/json"
"fmt"
)
func main() {
var dat interface{}
byt := []byte(`{"num":6.13,"strs":["a","b"]}`)
if err := json.Unmarshal(byt, &dat); err != nil {
panic(err)
}
fmt.Println(dat)
}
What you were trying to do makes no sense, since you're trying to unmarshal two JSON objects one into another.

Using Golang json.NewDecoder / json.NewEncoder

I'm a total noob at go and I'm trying to understand what I'm missing here. I'm expecting to use dec.Decode to loop over the json values and end up with a map of the response. What I'm getting is the entire json string as the key to the first element of the map. What am I missing?
Example response:
2015/03/02 10:03:16 map[error:invalid_request error_description:that is not a recognized WePay API call error_code:1001] map[string]interface {}
package main
import (
"encoding/json"
"io"
"log"
"net/http"
"reflect"
)
func main() {
var v map[string]interface{}
resp, err := http.Get("https://wepayapi.com/v2/")
if err != nil {
log.Println("Error: " + err.Error())
}
defer resp.Body.Close()
// resp.Body is an io.ReadCloser... NewDecoder expects an io.Reader
dec := json.NewDecoder(resp.Body)
// Decode reads the next JSON-encoded value from its input and stores it in the value pointed to by v.
for err := dec.Decode(&v); err != nil && err != io.EOF; {
log.Println("ERROR: " + err.Error())
return
}
log.Println(v, reflect.TypeOf(v))
}
Decoder will decode the whole JSON value at once (in this case the error object), you don;y have to call it in a loop:
if err := dec.Decode(&v); err != nil {
log.Println("ERROR: " + err.Error())
return
}
As a response you get a map equavalent of this JSON:
{"error":"invalid_request","error_description":"that is not a recognized WePay API call","error_code":1001}
Result:
map[string]interface{} {
"error":"invalid_request",
"error_description":"that is not a recognized WePay API call",
"error_code":1001,
}

Marshalling json.RawMessage returns base64 encoded string

I run the following code:
package main
import (
"encoding/json"
"fmt"
)
func main() {
raw := json.RawMessage(`{"foo":"bar"}`)
j, err := json.Marshal(raw)
if err != nil {
panic(err)
}
fmt.Println(string(j))
}
Playground: http://play.golang.org/p/qbkEIZRTPQ
Output:
"eyJmb28iOiJiYXIifQ=="
Desired output:
{"foo":"bar"}
Why does it base64 encode my RawMessage as if it was an ordinary []byte?
After all, RawMessage's implementation of MarshalJSON is just returning the byte slice
// MarshalJSON returns *m as the JSON encoding of m.
func (m *RawMessage) MarshalJSON() ([]byte, error) {
return *m, nil
}
Found the answer in a go-nuts thread
The value passed to json.Marshal must be a pointer for json.RawMessage to work properly:
package main
import (
"encoding/json"
"fmt"
)
func main() {
raw := json.RawMessage(`{"foo":"bar"}`)
j, err := json.Marshal(&raw)
if err != nil {
panic(err)
}
fmt.Println(string(j))
}