decode json including json encoded strings - json

Hey guys I am getting websocket information from external Api and it's give me json response in this way:
`{"name":"message","args":["{\"method\":\"chatMsg\",\"params\":{\"channel\":\"channel\",\"name\":\"name\",\"nameColor\":\"B5B11E\",\"text\":\"https://play.spotify.com/browse\",\"time\":1455397119}}"]}`
I am putting it into this struc
type main struct {
Name string `json:"name"`
Args []arg `json:"args"`
}
type arg struct {
Method string`json:"method"`
Params par `json:"params"`
}
type par struct {
Channel string `json:"channel,omitempty"`
Name string `json:"name,omitempty"`
NameColor string `json:"nameColor,omitempty"`
Text string `json:"text,omitempty"`
Time int64 `json:"time,omitempty"`
}
and decode it with code
sReplace := strings.NewReplacer(`"{`, "{", `"]`, "]", "\\", ``)
strN := sReplace.Replace(str)
r := strings.NewReader(strN)
d := json.NewDecoder(r)
m := main{}
I am getting error
invalid character 'h' after object key:value pair
I know that the error is result of text field value. Is there any good way to clean it up or tell the decoder to ignore content of text field?

The application is parsing data containing the substring "text":"<a href="https. This is not valid JSON. The error message is complaining about the h in href.
Because the JSON value includes encoded JSON values, the application must decode in two steps:
type main struct {
Name string `json:"name"`
Args []string `json:"args"`
}
type arg struct {
Method string `json:"method"`
Params par `json:"params"`
}
type par struct {
Channel string `json:"channel,omitempty"`
Name string `json:"name,omitempty"`
NameColor string `json:"nameColor,omitempty"`
Text string `json:"text,omitempty"`
Time int64 `json:"time,omitempty"`
}
str := `{"name":"message","args":["{\"method\":\"chatMsg\",\"params\":{\"channel\":\"channel\",\"name\":\"name\",\"nameColor\":\"B5B11E\",\"text\":\"https://play.spotify.com/browse\",\"time\":1455397119}}"]}`
var m main
if err := json.Unmarshal([]byte(str), &m); err != nil {
log.Fatal(err)
}
var args arg
if err := json.Unmarshal([]byte(m.Args[0]), &args); err != nil {
log.Fatal(err)
}
playground example

Related

How to take input as json string and later convert it to any object based on condition

Here I want to take DefaultResponse as String but later validate if it's a valid json before mapping to any json struct.
Complete code with validation can be found here :
https://go.dev/play/p/knGNMj1QG3l
type AddEndpointRequest struct {
Method string `json:"method"`
ContentType int `json:"contentType"`
DefaultStatusCode int `json:"defaultStatusCode"`
DefaultResponse string `json:"defaultResponse"`
}
I tried different option but none of them are working
if I pass this : “defaultResponse”:{“title”:“Buy cheese and bread for breakfast.”}
Getting error : json: cannot unmarshal object into Go struct field AddEndpointRequest.defaultResponse of type string
body := {"method":"GET","contentType":1,"defaultWaitTimeInMillis":100,"defaultStatusCode":200,"defaultResponse":"[{"p":"k"}]"}
Error : invalid character 'p' after object key:value pair
3)
body := {"method":"GET","contentType":1,"defaultWaitTimeInMillis":100,"defaultStatusCode":200,"defaultResponse":"{"p":"k"}"}
./prog.go:21:117: syntax error: unexpected { at end of statement
body := {"method":"GET","contentType":1,"defaultWaitTimeInMillis":100,"defaultStatusCode":200,"defaultResponse":"{/"p/":/"k/"}"} Error : ./prog.go:21:130: syntax error: unexpected literal "} at end of statement
And many more
Option A:
Declare the field as a string. Use a valid JSON string as the field value in the document. Note the escaping of the quotes in the string.
type AddEndpointRequest struct {
Method string `json:"method"`
ContentType int `json:"contentType"`
DefaultStatusCode int `json:"defaultStatusCode"`
DefaultResponse string `json:"defaultResponse"`
}
…
body := `{"method":"GET","contentType":1,"defaultWaitTimeInMillis":100,"defaultStatusCode":200,"defaultResponse":"{\"p\":\"k\"}"}`
Convert the field to a []byte to unmarshal:
err := json.Unmarshal([]byte(request.DefaultResponse), &data)
https://go.dev/play/p/ailgQQ3eQBH
Option B:
Declare the field as json.RawMessage. Use any valid JSON in the document.
type AddEndpointRequest struct {
Method string `json:"method"`
ContentType int `json:"contentType"`
DefaultStatusCode int `json:"defaultStatusCode"`
DefaultResponse json.RawMessage `json:"defaultResponse"`
}
…
body := `{"method":"GET","contentType":1,"defaultWaitTimeInMillis":100,"defaultStatusCode":200,"defaultResponse":{"p":"k"}}`
The call to json.Unmarshal([]byte(body), &request) validates the json.RawMessage field. If the call to json.Unmarshal does not return an error, then the application is assured that AddEndpointRequest.DefaultResponse contains valid JSON.
Unmarshal the field like this:
err := json.Unmarshal(request.DefaultResponse, &data)
https://go.dev/play/p/Xd_gWzJmvC_K
If you want to set a struct in defaultResponse, I think doing it like this should work.
package main
import (
"encoding/json"
"errors"
"fmt"
)
type AddEndpointRequest struct {
Method string `json:"method"`
ContentType int `json:"contentType"`
DefaultStatusCode int `json:"defaultStatusCode"`
DefaultResponse string `json:"defaultResponse"`
}
func main() {
body := `{"method":"GET","contentType":1,"defaultWaitTimeInMillis":100,"defaultStatusCode":200,"defaultResponse":{"title":"Buy cheese and bread for breakfast."}}`
fmt.Println("Hello GO")
err := validateBody(body)
if err != nil {
fmt.Println("erro102")
fmt.Println(err)
}
}
func validateBody(body string) error {
var data map[string]interface{}
err := json.Unmarshal([]byte(body), &data)
if err != nil {
return errors.New("invalid json body provided for the request")
}
fmt.Println("data===>", data)
fmt.Println("defaultResponse===>", data["defaultResponse"].(map[string]interface{})["title"])
return nil
}

Can't unmarshal json with base64 encoded byte slice in go

I'm having a hard time unmarshalling a struct that is sent to me from an AWS lambda function.
All of the pkidata fields are empty no matter what I do. I created this code sample to isolate the process :
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
)
func main() {
mystring := `{"error":{"errormessage": "errormessagetest", "errortype": "errortypetest"}, "pkidata":{"certificate":"Q2VydGlmaWNhdGU6CiAgICBEYXRhOgogICAgICAgIFZlcnNpb246IDMgKDB4MikKICAgICAgICBTZXJpYWwgTnVtYmVyOgogICAgICAgICAgICBhYTo5MzpiMTo4MDphYjpiYTplYzo5ZTo4MzpmOTo2OTo5NToyNDpkZjo5Njo2OQogICAgU2lnbmF0dXJlIEFsZ29yaXRobTogc2hhMjU2V2l0aFJTQUVuY3J5cHRpb24KICAgICAgICBJc3N1ZXI6IENOPXJhcGhvZXN0ZXIKICAgICAgICBWYWxpZGl0eQogICAgICAgICAgICBOb3QgQmVmb3JlOiBNYXIgMjcgMTk6NDM6MTQgMjAyMiBHTVQKICAgICAgICAgICAgTm90IEFmdGVyIDogSnVuIDI5IDE5OjQzOjE0IDIwMjQgR01UCiAgICAgICAgU3ViamVjdDogQ049cmFwaG9lc3RlcgogICAgICAgIFN1YmplY3QgUHVibGljIEtleSBJbmZvOgogICAgICAgICAgICBQdWJsaWMgS2V5IEFsZ29yaXRobTogcnNhRW5jcnlwdGlvbgogICAgICAgICAgICAgICAgUHVibGljLUtleTogKDIwNDggYml0KQogICAgICAgICAgICAgICAgTW9kdWx1czoKICAgICAgICAgICAgICAgICAgICAwMDpjNjplZjpkNjoxYTo0Mjo0Mjo2ZTo5MTpiODpmNTpiZjoyNToyNTpkODoKICAgICAgICAgICAgICAgICAgICBhNjo4Yjo4MzpmYjo2ZDo4MzpiNjowZTo3Mzo4ZjowYTozMjo5ZjpjNjplMjoKICAgICAgICAgICAgICAgICAgICBmMTo4Njo5NDoxMzo5MjplYjo0MTozNTo4NTpiZDo0ZDpkNzowNzo4ZTo5YjoKICAgICAgICAgICAgICAgICAgICBjYzoyYzpkMjo2Nzo5ZDpjOTo1Mzo4Yjo4ODpjZToxMTozOTpkODpkZTo3MjoKICAgICAgICAgICAgICAgICAgICBhMTphODo4MDozMDpmOTpiYTpiOTo3NTpjNTphMjoxYjpiZToyMDo3Yzo1ZjoKICAgICAgICAgICAgICAgICAgICBhMjpjZjpiNzphMjo2ODo4MzpiMzoxMTplODoyNTo3Mzo2MzoyNjphNzpiODoKICAgICAgICAgICAgICAgICAgICBjMzpjZDpjODplZTozNjphZjo4ZTo4ZjowZTo5NDowMToyMDpmZjowZTo0MToKICAgICAgICAgICAgICAgICAgICBjYjplZDpmYjo3NDowNToyZDo0NDphOToxNjoxZDo0ODpkNDphNDo3NTo0ZjoKICAgICAgICAgICAgICAgICAgICBlZjo0NDozYTphMDpmMDo1ZTo5ZTo5YjoxOTphZTo4MTozMzpkMDpkMTpmYzoKICAgICAgICAgICAgICAgICAgICA0MTphMTo1OTo5Zjo3MDoxZDphYTo3MzoyNTpiNTpiNjo3NDo2Mzo1NzpjZjoKICAgICAgICAgICAgICAgICAgICAzNTplNzpiZToyNjo1MzoxNDpkNTplNzpiMzpmYToyZDpjYzo5NToyMzo0ODoKICAgICAgICAgICAgICAgICAgICBkOTpkNTozNDplMjowNzoxYjoyNzoyMzpiZTpiODpmNzpiNTpkOTo3MDo1ZDoKICAgICAgICAgICAgICAgICAgICAyOTo4NTo3NToyYjpmYTo0MjpmNTo2Mjo1OTozZjowODo3Njo0Nzo2NjpmNzoKICAgICAgICAgICAgICAgICAgICAxYzpiYzozNzo1MjpiMDo3ODoyNzozNDo3MTo3ZTpiNjozZDowNDpjZDoyMzoKICAgICAgICAgICAgICAgICAgICAzMjphNjoxYTo2NzphNDo4ODoyYTowYTpmMjoxMjphNTo3ODpkYjpiZDpjOToKICAgICAgICAgICAgICAgICAgICA1ZToxMTo4Njo0MDpkMTo0MTplZjpkYzo2Yjo4Zjo1NjpmZDo1MjpkYTo0ZjoKICAgICAgICAgICAgICAgICAgICBiNTpmMDozYTpmZTpjNzoxMDo3ZTpjNDo3OTo2MTo1ZTpkYjo5Zjo4NjpjOToKICAgICAgICAgICAgICAgICAgICBmYjpiNwogICAgICAgICAgICAgICAgRXhwb25lbnQ6IDY1NTM3ICgweDEwMDAxKQogICAgICAgIFg1MDl2MyBleHRlbnNpb25zOgogICAgICAgICAgICBYNTA5djMgQmFzaWMgQ29uc3RyYWludHM6IAogICAgICAgICAgICAgICAgQ0E6RkFMU0UKICAgICAgICAgICAgWDUwOXYzIFN1YmplY3QgS2V5IElkZW50aWZpZXI6IAogICAgICAgICAgICAgICAgMDU6M0Y6RDk6MjE6Rjg6MUE6QjM6NDM6OEQ6QzI6NDA6NzI6OUY6MDE6NDg6MTc6NDE6Nzc6Q0U6MzkKICAgICAgICAgICAgWDUwOXYzIEF1dGhvcml0eSBLZXkgSWRlbnRpZmllcjogCiAgICAgICAgICAgICAgICBrZXlpZDozNTpCRjpBOTozRDo1RjozMzozODowQjowNjo3QzpDQTpFQzo0ODo3QzpCRTo3Njo3MzpCRTpEQjpGRQogICAgICAgICAgICAgICAgRGlyTmFtZTovQ049cmFwaG9lc3RlcgogICAgICAgICAgICAgICAgc2VyaWFsOjhGOjE3OkY1OjJBOjhBOkI0OkQwOjY5CgogICAgICAgICAgICBYNTA5djMgRXh0ZW5kZWQgS2V5IFVzYWdlOiAKICAgICAgICAgICAgICAgIFRMUyBXZWIgU2VydmVyIEF1dGhlbnRpY2F0aW9uCiAgICAgICAgICAgIFg1MDl2MyBLZXkgVXNhZ2U6IAogICAgICAgICAgICAgICAgRGlnaXRhbCBTaWduYXR1cmUsIEtleSBFbmNpcGhlcm1lbnQKICAgICAgICAgICAgWDUwOXYzIFN1YmplY3QgQWx0ZXJuYXRpdmUgTmFtZTogCiAgICAgICAgICAgICAgICBETlM6cmFwaG9lc3RlcgogICAgU2lnbmF0dXJlIEFsZ29yaXRobTogc2hhMjU2V2l0aFJTQUVuY3J5cHRpb24KICAgICAgICAgNTg6M2U6MTE6ZmQ6OWM6ZWQ6MTA6YmQ6NmM6NWE6OWY6NzY6OGY6OTc6MGE6YTY6Mzg6ODI6CiAgICAgICAgIDFhOmYwOmJlOjRiOmU4OjEwOmQ4OjNlOmFhOmFlOjIwOmNiOmMzOjI2OjY1OmU3OmI3OmM3OgogICAgICAgICBjNzo2MToxZTpjNjplMjpjYTpmODo1NTo4ZTpkODoxNjozODphZjo3ZjphZDo3Mjo1MzoxYzoKICAgICAgICAgNmE6MzI6NjE6M2U6ZDM6M2E6NWI6NTg6OTU6NDU6ZGE6MGQ6ZTg6ZjQ6NDM6ZWY6NmY6ZmM6CiAgICAgICAgIDE4OmQxOjA4OjA5OjZlOmQ5OjRmOmQ3OjljOmU2OjliOjAzOmU3OjczOjhkOjExOjNhOjkyOgogICAgICAgICBiMDozYTpjOTpiNDo2MjpmNDphODpiMTphMDo0MzpkMzplODoyZjphZDo5Yjo4ZjoyZjpjZjoKICAgICAgICAgZTA6ZTY6YzE6MWM6MDc6N2E6OWY6YjM6NTI6NWU6MzM6ZWU6MjE6NjY6YTU6MDE6YjA6MzQ6CiAgICAgICAgIDUzOjY5OmRjOjIwOmYyOmY4OmJjOjEyOjJiOjNkOjkyOjM3OjdhOjY3OjZiOmJkOjkzOmZlOgogICAgICAgICA1NTpiMTo5YTo4Yjo5NTpiOTpjMDpkYzpiOToxMTo1MDo5ODoyNjo0MzpkOTpkZTo5ZTo2NzoKICAgICAgICAgZTE6NWE6MmI6YTI6ZmU6YWY6ZDE6ODY6NTQ6N2Y6YzE6NjE6Y2E6ZWQ6NjY6N2Y6YWY6ODQ6CiAgICAgICAgIGFiOjAyOmY5OjBhOmUyOmJkOjFhOjQ1OjgzOmU3OjM1Ojc4OjNkOjAzOmRkOjY4OjkyOjhlOgogICAgICAgICA2YTpkODpjZDoyYToxMzplYzphOTowMjo5OTo1Yzo3ZDplZDowMzo2Mzo5Mzo2MDo1ZTpiYToKICAgICAgICAgNDg6ODM6Zjc6ODA6YzA6YzQ6ZDU6YjM6NjI6NGE6MmM6Njc6NTE6YzA6MmM6MDE6NmU6OWM6CiAgICAgICAgIDNkOmExOjQ2OjcwOjZmOmUwOjIxOmYxOjE5OjE1OjJiOmZmOjQwOjNmOjk4OjdlOjMwOjI3OgogICAgICAgICAxYzplZTo5ZDo3ZQotLS0tLUJFR0lOIENFUlRJRklDQVRFLS0tLS0KTUlJRFl6Q0NBa3VnQXdJQkFnSVJBS3FUc1lDcnV1eWVnL2xwbFNUZmxta3dEUVlKS29aSWh2Y05BUUVMQlFBdwpGVEVUTUJFR0ExVUVBd3dLY21Gd2FHOWxjM1JsY2pBZUZ3MHlNakF6TWpjeE9UUXpNVFJhRncweU5EQTJNamt4Ck9UUXpNVFJhTUJVeEV6QVJCZ05WQkFNTUNuSmhjR2h2WlhOMFpYSXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUEKQTRJQkR3QXdnZ0VLQW9JQkFRREc3OVlhUWtKdWtiajF2eVVsMkthTGcvdHRnN1lPYzQ4S01wL0c0dkdHbEJPUwo2MEUxaGIxTjF3ZU9tOHdzMG1lZHlWT0xpTTRST2RqZWNxR29nREQ1dXJsMXhhSWJ2aUI4WDZMUHQ2Sm9nN01SCjZDVnpZeWFudU1QTnlPNDJyNDZQRHBRQklQOE9RY3Z0KzNRRkxVU3BGaDFJMUtSMVQrOUVPcUR3WHA2YkdhNkIKTTlEUi9FR2hXWjl3SGFwekpiVzJkR05YenpYbnZpWlRGTlhucy9vdHpKVWpTTm5WTk9JSEd5Y2p2cmozdGRsdwpYU21GZFN2NlF2VmlXVDhJZGtkbTl4eThOMUt3ZUNjMGNYNjJQUVROSXpLbUdtZWtpQ29LOGhLbGVOdTl5VjRSCmhrRFJRZS9jYTQ5Vy9WTGFUN1h3T3Y3SEVIN0VlV0ZlMjUrR3lmdTNBZ01CQUFHamdhMHdnYW93Q1FZRFZSMFQKQkFJd0FEQWRCZ05WSFE0RUZnUVVCVC9aSWZnYXMwT053a0J5bndGSUYwRjN6amt3UlFZRFZSMGpCRDR3UElBVQpOYitwUFY4ek9Bc0dmTXJzU0h5K2RuTysyLzZoR2FRWE1CVXhFekFSQmdOVkJBTU1DbkpoY0dodlpYTjBaWEtDCkNRQ1BGL1VxaXJUUWFUQVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBVEFMQmdOVkhROEVCQU1DQmFBd0ZRWUQKVlIwUkJBNHdESUlLY21Gd2FHOWxjM1JsY2pBTkJna3Foa2lHOXcwQkFRc0ZBQU9DQVFFQVdENFIvWnp0RUwxcwpXcDkyajVjS3BqaUNHdkMrUytnUTJENnFyaURMd3labDU3Zkh4MkVleHVMSytGV08yQlk0cjMrdGNsTWNhakpoClB0TTZXMWlWUmRvTjZQUkQ3Mi84R05FSUNXN1pUOWVjNXBzRDUzT05FVHFTc0RySnRHTDBxTEdnUTlQb0w2MmIKankvUDRPYkJIQWQ2bjdOU1hqUHVJV2FsQWJBMFUybmNJUEw0dkJJclBaSTNlbWRydlpQK1ZiR2FpNVc1d055NQpFVkNZSmtQWjNwNW40Vm9yb3Y2djBZWlVmOEZoeXUxbWY2K0Vxd0w1Q3VLOUdrV0Q1elY0UFFQZGFKS09hdGpOCktoUHNxUUtaWEgzdEEyT1RZRjY2U0lQM2dNREUxYk5pU2l4blVjQXNBVzZjUGFGR2NHL2dJZkVaRlN2L1FEK1kKZmpBbkhPNmRmZz09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K","privatekey":"LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2QUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktZd2dnU2lBZ0VBQW9JQkFRREc3OVlhUWtKdWtiajEKdnlVbDJLYUxnL3R0ZzdZT2M0OEtNcC9HNHZHR2xCT1M2MEUxaGIxTjF3ZU9tOHdzMG1lZHlWT0xpTTRST2RqZQpjcUdvZ0RENXVybDF4YUlidmlCOFg2TFB0NkpvZzdNUjZDVnpZeWFudU1QTnlPNDJyNDZQRHBRQklQOE9RY3Z0CiszUUZMVVNwRmgxSTFLUjFUKzlFT3FEd1hwNmJHYTZCTTlEUi9FR2hXWjl3SGFwekpiVzJkR05YenpYbnZpWlQKRk5YbnMvb3R6SlVqU05uVk5PSUhHeWNqdnJqM3RkbHdYU21GZFN2NlF2VmlXVDhJZGtkbTl4eThOMUt3ZUNjMApjWDYyUFFUTkl6S21HbWVraUNvSzhoS2xlTnU5eVY0UmhrRFJRZS9jYTQ5Vy9WTGFUN1h3T3Y3SEVIN0VlV0ZlCjI1K0d5ZnUzQWdNQkFBRUNnZ0VBV0loMzhpdTJ3TnBkUkJDVENhckhRNk96QzJQb2E3b0YySFg3SVZueVB3QTcKVGRFZ3JoOGN4ajJDQVhkWWdFSUxGdTk0SE1yL1dpOHlVcDBWVUpYc05kZGhuZ1ljUk5oeVFLZVhIM1lMOHhOWgphQWkyVWdtNE5FQkg4NWNPWEl2NGw3WFhMRUZ4QVBsTE5sZ0hwQjRuUmxDdks3Qm1tRWJBcHM2b3ZSQis2V3JVCkRBWTc0UDNPTi9EMmxyczVNSzlCdlA1d0FsZml1L0x3MTV4NE1UVEE2MkxHNU1remUxV2d0VGtXdnN0VUNXZUUKYW9zQ21tbVhwUGJvR2ZzRXcvSGpWdnZ6UFNKMDhid0U0Mlk2VUFtMGgzWjdMQ1o5ajJtazBsS2NpdStzYndoKwpGL3VvZHdMc2d3bGErNGFGN3g4ZW9rb0RCeVRjVSt1VUVaZWR3MEVKb1FLQmdRRC92ejhFTkM3Q3pSR2VBWjR0Cjhobkdnd2FjbXRjRmVHTHVWVG5iY3ZIZ2EwbVpabk5jdHdpRVlHMm9CYWtkWFcwTmN5WU1tQWlFZXczNTk2Q3QKakxzY0ViSEhMYmV4OGNHWTZlM3gwRFhPTkVGYlBNUnFUTWtIZytIS2tHbWxES3EzUkNxc2RzYnd3T3EyaEd6dApCNnp2SHNuUXlXeEtnMlE2bXVhckpXaUpYd0tCZ1FESElqVEUrQ2pTWkVvZ0E3dG1zN1NkR0cyY0NjNnB0RWRrCmZPZWFGVzJPWDlia2JjakxXcm9zRmpSVm1nbVRXSFZNcnBmR3p5aVBKTWNtanZxbnQzYklVU2JXK2xKMWdZL0sKSTkyL3Q0K09PRTRUL0xYZ09Hc2lOajh1R3ZTMkt2VnNXOE4yMW8vMkE3TklDcEZlTlFuRnFpcW1vazRzV1FjdAprUCtVc3lBMHFRS0JnRUViUXNPak5UUktXRzNOSTZPMnVuRWE4aGYwSTBFMVFKcEVBQktwMUlHNVRtZEsrWnRrCnpUcEdBaVNBTEdsWlcyWE5KcWFXSGJUOFRyYVFIOHVPeENPRkxhanpMb3lTYXlLdWl2REFmTEllQTNWaXB1NFkKMWlTZm9sK2JIQW4waTVGVVBUamlsQXErVWdKYy9BM3JvazdObTdzWFRBWThKTXYybXpwK3Izb3BBb0dBZit1bApZbkxZSm05dWZxcG5GRTZVMCtZQlk1K1pOc01zcVl6amFzUWhJTGpJWHUxM2M4clFsY21kek8rcS94QndLZFp1CmdiUktKY3BHZEtxY3NtalUwVkh3VldGdzN6TmZuMGJ6Q0ZsdXlybTR6bllraitrdVNVZjN4akppeVROSGZWaGwKZEUzWkpQeXppcS9mT2xsdjhaNml6M0NzTHlqeHgzL0I3MUF5ZkNFQ2dZQk5KckJEdnRSZDRCbmVXQjI5Mk84MQpBU0JpWnNPaHFDMnhSWWg1YnYyVFA2clpQd0h0cGV5MmJEK21iQVpLd003TDRKeHJxK3c0aERTN2EwRlowUm1rCi9yRlpvSjR3MDZWNGM2ZndyZG9WZmRvWE5zNkViQmd1ekxab0YyOFNUc3pOZGhFelJkdFNyWWxlalM1UnVDV2UKbUJ1L0g1d1lBNFFtUU9hRzMranFVZz09Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K","certificatechain":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURNakNDQWhxZ0F3SUJBZ0lKQUk4WDlTcUt0TkJwTUEwR0NTcUdTSWIzRFFFQkN3VUFNQlV4RXpBUkJnTlYKQkFNTUNuSmhjR2h2WlhOMFpYSXdIaGNOTWpJd016STNNVGswTXpBMVdoY05Nekl3TXpJME1UazBNekExV2pBVgpNUk13RVFZRFZRUUREQXB5WVhCb2IyVnpkR1Z5TUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCCkNnS0NBUUVBdUlqRXJzc0hHSFR3TmNFbjhVTmlKQjErQ0lzL2Q2aklVaXRjUlFJcEhseVJPYzMxaDNyOGlkV0oKK2pGNkFSSndXQThIcmRKYTVCTFhYK3BMWWtMblQ1V2xBVjZkNi9FT2xoUDlCM2tyNHE2ODB0TFhUM3J3UitOdAo0ZTZ0MnUzbjFIS0tsMGM0U25xRGY2b1NjRzE5SGh5OWcvbmp6eFpLVXhZd21tWDRZZXdsSnZNSXZ0VnA5M2JFClQ1MjdJdk5lcFN4MXBBTmhtLzVTRW1zQ3MwQ2pENmZZOXNrcWUra3piZE1TOFhNZlZQYkVXUzdjcG9lZERpSFEKdTVRQVhjSmxnRUVCTjMvbG5JZEpxQ0xQOEFTV2hWd3puSmNEemc5UEcrTlZ4S1A1MHV0bDdROHdsd0Z0R2d4UAp5REhvamNsbVBtQ291UmdHb2RrMnJBQ0lYME9PTFFJREFRQUJvNEdFTUlHQk1CMEdBMVVkRGdRV0JCUTF2Nms5Clh6TTRDd1o4eXV4SWZMNTJjNzdiL2pCRkJnTlZIU01FUGpBOGdCUTF2Nms5WHpNNEN3Wjh5dXhJZkw1MmM3N2IKL3FFWnBCY3dGVEVUTUJFR0ExVUVBd3dLY21Gd2FHOWxjM1JsY29JSkFJOFg5U3FLdE5CcE1Bd0dBMVVkRXdRRgpNQU1CQWY4d0N3WURWUjBQQkFRREFnRUdNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUUN6YXU1QlNnSituZy92Cnd2SHVDTnEyZWg5c1M1M3pmVUlQeTZqTUZrZHprelVZTmI1WjFRK1hjb21GbU9xOVVmaWcxN2dZdUR3WC9nMlMKVklDMVJDdWxwVTNORnNLOEhrSDdjdVFPOGNjSnlWc3JtUndPSFhabmtwTnBoYXI4RFQvSjU5d3FNU09ZZUJQYgpuQU41T0piaUF0NlRBNmRsUXJidkFvWG04dXdHMjFSU1N1VHQ5UElsY3NGallQazhiQWJ0dXdldEVnYjVuNkhoClhhczA1S0dteENmZDZxNHAxYUxITkVpNTVSejg0bEVsVHVNZlA0ZEwyZjIzUnFncmpEQmNDRmEwN1owZHJNdjcKbERYNEovaVpXY08zWXJJWXppcVg5M015UzNSUCtrYXAvV0dIYlZDcWtpZ2lTODZwQkY1NDh3OWxXQ0xJai9kTgozRTI2V24zNgotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg=="}}`
// yeah the string is long lol
var body ResponseBody
if err := json.Unmarshal([]byte(mystring), &body); err != nil {
fmt.Println(fmt.Errorf("failed unmarshaling response | %s", err.Error()))
}
fmt.Println(body.Error.ErrorMessage)
certChain, err := base64.StdEncoding.DecodeString(mystring)
if err != nil {
fmt.Println(err.Error())
}
fmt.Println(certChain)
}
type PkiGenerationInput struct {
TeacherUsername string `json:"teacherusername"`
}
type Response struct {
Headers ResponseHeaders `json:"headers"`
Body ResponseBody `json:"body"`
}
type ResponseHeaders struct {
ContentType string `json:"Content-Type"`
}
type ResponseBody struct {
PkiData ParsablePkiData `json:"pkidata"`
Error struct {
ErrorMessage string `json:"errormessage"`
ErrorType string `json:"errortype"`
} `json:"error"`
}
type ParsablePkiData struct {
Certificate string `json:"certificate"`
PrivateKey string `json:"privatekey"`
CertificateChain string `json:"certificatechain"`
}
Here is the output
errormessagetest
illegal base64 data at input byte 0
[]
the fact I can read the errormessagetest shows that the unmarshalling kinda works, so that's weird.
I checked for any unexported fields but we can clearly see they are all capitalized. I also reduced the string size "just to see" and it didn't change anything.
Answer to synthetize all of the comments :
First of all, my "dumb mistake" was because I tried to decode the wrong variable :
// mystring needs to be replaced by body.PkiData.Certificate
base64.StdEncoding.DecodeString(mystring)
But the research led us to discover that the json.Unmarshal() function decodes base64 by itself when the result type matches what the declared type. Given the fact the encoded data was a []byte, I just replaced the string type by a []byte in the struct.
That allows to create a much more simple version of the previous code :
type ResponseBody struct {
PkiData PkiData `json:"pkidata"`
}
type PkiData struct {
Certificate []byte
PrivateKey []byte
CertificateChain []byte
}
var body ResponseBody
if err := json.Unmarshal(rawResp.Payload, &body); err != nil {
return PkiData{}, fmt.Errorf("failed unmarshaling response | %s", err.Error())
}

Decode JSON value which can be either string or number

When I make an HTTP call to a REST API I may get the JSON value count back as a Number or String. I'ld like to marshal it to be an integer in either case. How can I deal with this in Go?.
Use the "string" field tag option to specify that strings should be converted to numbers. The documentation for the option is:
The "string" option signals that a field is stored as JSON inside a JSON-encoded string. It applies only to fields of string, floating point, integer, or boolean types. This extra level of encoding is sometimes used when communicating with JavaScript programs:
Here's an example use:
type S struct {
Count int `json:"count,string"`
}
playground example
If the JSON value can be number or string, then unmarshal to interface{} and convert to int after unmarshaling:
Count interface{} `json:"count,string"`
Use this function to convert the interface{} value to an int:
func getInt(v interface{}) (int, error) {
switch v := v.(type) {
case float64:
return int(v), nil
case string:
c, err := strconv.Atoi(v)
if err != nil {
return 0, err
}
return c, nil
default:
return 0, fmt.Errorf("conversion to int from %T not supported", v)
}
}
// Format of your expected request
type request struct {
ACTIVE string `json:"active"`
CATEGORY string `json:"category"`
}
// struct to read JSON input
var myReq request
// Decode the received JSON request to struct
decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&myReq)
if err != nil {
log.Println( err)
// Handler for invalid JSON received or if you want to decode the request using another struct with int.
return
}
defer r.Body.Close()
// Convert string to int
numActive, err = strconv.Atoi(myReq.ACTIVE)
if err != nil {
log.Println(err)
// Handler for invalid int received
return
}
// Convert string to int
numCategory, err = strconv.Atoi(myReq.CATEGORY)
if err != nil {
log.Println(err)
// Handler for invalid int received
return
}
I had the same problem with a list of values where the values were string or struct. The solution I'm using is to create a helper struct with fields of expected types and parse value into the correct field.
type Flag struct {
ID string `json:"id"`
Type string `json:"type"`
}
type FlagOrString struct {
Flag *Flag
String *string
}
func (f *FlagOrString) UnmarshalJSON(b []byte) error {
start := []byte("\"")
for idx := range start {
if b[idx] != start[idx] {
return json.Unmarshal(b, &f.Flag)
}
}
return json.Unmarshal(b, &f.String)
}
var MainStruct struct {
Vals []FlagOrString
}
Custom Unmarshaller simplifies a code. Personally I prefer this over interface{} as it explicitly states what a developer expects.

Golang decode 2 JSON items into 1 struct

i'm trying to decode 2 JSON items into the same struct, because the second JSON complet the first one, but it doesn't work (do nothing) have you got some ideas ?
func getUserClip(this *LibraryController, id string) (*Clip){
//Test Api
//Send Request to azure search
Data := Clip{}
if req := GetClipById("b373400a-bd7e-452a-af68-36992b0323a5"); req == nil {
return nil
} else {
str, err := req.String()
if err != nil {
beego.Debug("Error Json req.String: ", err)
}
//Uncode Json to string
if err := json.Unmarshal([]byte(str), &Data); err != nil {
beego.Debug("Error json", err)
}
for i := range Data.Value {
if req = GetCliRedis(Data.Value[i].Id); err != nil {
return nil
} else {
str, err := req.String()
beego.Debug("JSON REDIS DEBUG: ", str)
if err != nil {
beego.Debug("Error Json req.String: ", err)
}
if err := json.Unmarshal([]byte(str), &Data); err != nil {
beego.Debug("Error json", err)
}
}
i++
}
}
return &Data
}
and the struct
type Clip struct {
Value []InfoClip `json:value`
}
type InfoClip struct {
Id string `json:id`
CreatedAt time.Time `json:createdAt`
StartTimeCode int `json:startTimeCode`
EndTimeCode int `json:endTimeCode`
Metas metas `json:metas`
Tags []string `json:tags`
Categories []string `json:categories`
UserId string `json:userId`
SourceId string `json:sourceId`
ProviderName string `json:providerName`
ProviderReference string `json:providerReference`
PublicationStatus string `json:publicationStatus`
Name string `json:name`
FacebookPage string `json:facebookPage`
TwitterHandle string `json:twitterHandle`
PermaLinkUrl string `json:permalinkUrl`
Logo string `json:logo`
Link string `json:link`
Views int `json:views`
}
type metas struct {
Title string `json:title`
Tags []string `json:tags`
Categories []string `json:categories`
PermaLink string `json:permalink`
}
The JSON I receive is:
{
"clipId":"9b2ea9bb-e54b-4291-ba16-9211fa3c755f",
"streamUrl":"https://<edited out>/asset-32e43a5d-1500-80c3-cc6b-f1e4fe2b5c44\/6c53fbf5-dbe9-4617-9692-78e8d76a7b6e_H264_500kbps_AAC_und_ch2_128kbps.mp4?sv=2012-02-12&sr=c&si=17ed71e8-5176-4432-8092-ee64928a55f6&sig=KHyToRlqvwQxWZXVvRYOkBOBOF0SuBLVmKiGp4joBpw%3D&st=2015-05-18T13%3A32%3A41Z&se=2057-05-07T13%3A32%3A41Z",
"startTimecode":"6",
"endTimecode":"16",
"createdAt":"2015-05-19 13:31:32",
"metas":"{\"title\":\"Zapping : Obama, Marine Le Pen et Michael Jackson\",\"tags\":[\"actualite\"],\"categories\":[\"actualite\"],\"permalink\":\"http:\/\/videos.lexpress.fr\/actualite\/zapping-obama-marine-le-pen-et-michael-jackson_910357.html\"}",
"sourceId":"6c53fbf5-dbe9-4617-9692-78e8d76a7b6e",
"providerName":"dailymotion",
"providerReference":"x1xmnxq",
"publicationStatus":"1",
"userId":"b373400a-bd7e-452a-af68-36992b0323a5",
"name":"LEXPRESS.fr",
"facebookPage":"https:\/\/www.facebook.com\/LExpress",
"twitterHandle":"https:\/\/twitter.com\/lexpress",
"permalinkBaseURL":"https:\/\/tym.net\/fr\/{CLIP_ID}",
"logo":"lexpress-120px.png",
"link":"http:\/\/videos.lexpress.fr\/"
}
The Redis complet the azure search missing information :
here the struct :
type Clip struct {
Value []SearchClip `json:value`
}
type SearchClip struct {
Id string `json:id`
CreatedAt string`json:createdAt`
Tags []string `json:tags`
Categories []string `json:categories`
UserId string `json:userId`
SourceId string `json:sourceId`
Views int `json:views`
}
this is the basic information and redis complet this
I don't want to merge 2 struct into a third one i think it's not the better process, i will do it if it's the last solution.
For lack of activity I'm just gonna post the embedding option as a solution. It's probably the simplest way to do what you want.
type ClipInfoAndMeta struct {
Metas
InfoClip
}
Note I upper cased the name on metas not sure it's necessary but I believe it will be. The language feature being used here is called 'embedding' and it works a lot like composition except that the fields/methods for embedded types are more or less 'hoisted' to the containing types scope. IE with an instance of ClipInfoAndMeta you can directly access any exported field that is defined on InfoClip.
One oddity of your set up is that you'll have collisions on field names between the two types. Not sure how that would play out. With all this being said, it would be helpful to see the json string you're trying to Unmarshal from. As I've been writing this I realized that metas is just a subset of InfoClip. Which has confused me about what you are actually trying to do? I mean, if the data coming back is all in one object, it would mean InfoClip is sufficient for storing all of it. If that is the case you have no reason for the other object... And if you want to trim down the fields which get passed to the display layer of your app you should just define a method on the InfoClip type like func (i *InfoClip) GetMetas() Metas { return &Metas{ ... } } then you can just deal with the one type everywhere and hand off the Metas to the display layer when it's needed.
After a lot of trial and error, I present to you this fully functional solution:
package main
import (
"encoding/json"
"fmt"
"log"
"time"
)
type Clip struct {
Value []InfoClip `json:value`
}
type customTime struct {
time.Time
}
const ctLayout = "2006-01-02 15:04:05"
func (ct *customTime) UnmarshalJSON(b []byte) (err error) {
if b[0] == '"' && b[len(b)-1] == '"' {
b = b[1 : len(b)-1]
}
ct.Time, err = time.Parse(ctLayout, string(b))
return
}
type InfoClip struct {
Id string `json:"clipId"`
CreatedAt customTime `json:"createdAt"`
StartTimeCode string `json:"startTimeCode"` //if you want ints here, you'll have to decode manually, or fix the json beforehand
EndTimeCode string `json:"endTimeCode"` //same for this one
Metas metas `json:"-"`
MetasString string `json:"metas"`
Tags []string `json:"tags"`
Categories []string `json:"categories"`
UserId string `json:"userId"`
SourceId string `json:"sourceId"`
ProviderName string `json:"providerName"`
ProviderReference string `json:"providerReference"`
PublicationStatus string `json:"publicationStatus"`
Name string `json:"name"`
FacebookPage string `json:"facebookPage"`
TwitterHandle string `json:"twitterHandle"`
PermaLinkUrl string `json:"permalinkBaseURL"`
Logo string `json:"logo"`
Link string `json:"link"`
Views int `json:"views"`
}
type metas struct {
Title string `json:"title"`
Tags []string `json:"tags"`
Categories []string `json:"categories"`
PermaLink string `json:"permalink"`
}
var jsonString = `{
"clipId":"9b2ea9bb-e54b-4291-ba16-9211fa3c755f",
"streamUrl":"https://<edited out>/asset-32e43a5d-1500-80c3-cc6b-f1e4fe2b5c44\/6c53fbf5-dbe9-4617-9692-78e8d76a7b6e_H264_500kbps_AAC_und_ch2_128kbps.mp4?sv=2012-02-12&sr=c&si=17ed71e8-5176-4432-8092-ee64928a55f6&sig=KHyToRlqvwQxWZXVvRYOkBOBOF0SuBLVmKiGp4joBpw%3D&st=2015-05-18T13%3A32%3A41Z&se=2057-05-07T13%3A32%3A41Z",
"startTimecode":"6",
"endTimecode":"16",
"createdAt":"2015-05-19 13:31:32",
"metas":"{\"title\":\"Zapping : Obama, Marine Le Pen et Michael Jackson\",\"tags\":[\"actualite\"],\"categories\":[\"actualite\"],\"permalink\":\"http:\/\/videos.lexpress.fr\/actualite\/zapping-obama-marine-le-pen-et-michael-jackson_910357.html\"}",
"sourceId":"6c53fbf5-dbe9-4617-9692-78e8d76a7b6e",
"providerName":"dailymotion",
"providerReference":"x1xmnxq",
"publicationStatus":"1",
"userId":"b373400a-bd7e-452a-af68-36992b0323a5",
"name":"LEXPRESS.fr",
"facebookPage":"https:\/\/www.facebook.com\/LExpress",
"twitterHandle":"https:\/\/twitter.com\/lexpress",
"permalinkBaseURL":"https:\/\/tym.net\/fr\/{CLIP_ID}",
"logo":"lexpress-120px.png",
"link":"http:\/\/videos.lexpress.fr\/"
}`
func main() {
res := parseJson(jsonString)
fmt.Printf("%+v\n",res)
}
func parseJson(theJson string) InfoClip {
toParseInto := struct {
InfoClip
MetasString string `json:"metas"`
}{
InfoClip: InfoClip{},
MetasString: ""}
err := json.Unmarshal([]byte(jsonString), &toParseInto)
if err != nil {
log.Panic(err)
}
err = json.Unmarshal([]byte(toParseInto.MetasString), &toParseInto.InfoClip.Metas)
if err != nil {
log.Panic(err)
}
return toParseInto.InfoClip
}
What are we doing in the parseJson function?
We create a new struct and assign that to the toParseInto variable. We design the struct in a way that it contains all of the fields from InfoClip via embedding, and We add a field to temporarily hold the JSON string metas.
We then unmarshal into that struct, which, after fixing the issues listed below, works fine.
After that, we unmarshal that inner JSON into the correct field in the embedded InfoClip.
We can now easily return that embedded InfoClip to get what we really wanted.
Now, all the issues I have identified in your original solution:
The time format in your JSON is not the standard time format to be used in JSON. That is defined in some RFC, but anyways: because of that, we have to use our own type customTime to parse that. It handles just like a normal time.Time, because that is embedded within.
All your json tags were wrong. All of them had missing quotes, and some were just not even correct.
startTimeCode and endTimeCode are strings in the JSON, not ints
Left to you to improve:
Error handling: Don't just panic in the parseJson function, but rather return the error somehow
If you want startTimecode and endTimecode to be available as ints, parse them manually. You can employ a "hack" similar to the one I used to parse the inner JSON.
One final note, not related to this answer but rather to your question: If you had provided both your code and the JSON with your original question, you would have had an answer in probably less than an hour. Please, please don't make this harder than it needs to be.
EDIT: I forgot to provide my sources, I used this question to parse your time format.

Cannot unmarshal string into Go value of type int64

I have struct
type tySurvey struct {
Id int64 `json:"id,omitempty"`
Name string `json:"name,omitempty"`
}
I do json.Marshal write JSON bytes in HTML page. jQuery modifies name field in object and encodes object using jQueries JSON.stringify and jQuery posts string to Go handler.
id field encoded as string.
Sent: {"id":1} Received: {"id":"1"}
Problem is that json.Unmarshal fails to unmarshal that JSON because id is not integer anymore.
json: cannot unmarshal string into Go value of type int64
What is best way to handle such data? I do not wish to manually convert every field. I wish to write compact, bug free code.
Quotes is not too bad. JavaScript does not work well with int64.
I would like to learn the easy way to unmarshal json with string values in int64 values.
This is handled by adding ,string to your tag as follows:
type tySurvey struct {
Id int64 `json:"id,string,omitempty"`
Name string `json:"name,omitempty"`
}
This can be found about halfway through the documentation for Marshal.
Please note that you cannot decode the empty string by specifying omitempty as it is only used when encoding.
use json.Number
type tySurvey struct {
Id json.Number `json:"id,omitempty"`
Name string `json:"name,omitempty"`
}
You could also create a type alias for int or int64 and create a custom json unmarshaler
Sample code:
Reference
// StringInt create a type alias for type int
type StringInt int
// UnmarshalJSON create a custom unmarshal for the StringInt
/// this helps us check the type of our value before unmarshalling it
func (st *StringInt) UnmarshalJSON(b []byte) error {
//convert the bytes into an interface
//this will help us check the type of our value
//if it is a string that can be converted into a int we convert it
///otherwise we return an error
var item interface{}
if err := json.Unmarshal(b, &item); err != nil {
return err
}
switch v := item.(type) {
case int:
*st = StringInt(v)
case float64:
*st = StringInt(int(v))
case string:
///here convert the string into
///an integer
i, err := strconv.Atoi(v)
if err != nil {
///the string might not be of integer type
///so return an error
return err
}
*st = StringInt(i)
}
return nil
}
func main() {
type Item struct {
Name string `json:"name"`
ItemId StringInt `json:"item_id"`
}
jsonData := []byte(`{"name":"item 1","item_id":"30"}`)
var item Item
err := json.Unmarshal(jsonData, &item)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%+v\n", item)
}