I have JSON object response returned from the server which is similar to this one:
{
"id": 123,
"from_id": 234,
"attachments": [
{
"type": "audio",
"audio": {
"artist": "Van Halen",
"title": "Eruption"
}
},
{
"type": "photo",
"photo": {
"id": 123,
"url": "http://someurl.com"
}
}
]
}
and I want to unmarshal it to the following structure:
type Response struct {
Id int `json:"id"`
FromId int `json:"from_id"`
Attachments []Attachment
}
where Attachment is described like this
type Attachment struct {
Type string
Fields map[string]interface{}
}
and Fields field is map that contains fields from "photo" or "audio" object of attachment in JSON.
Here is the code I've written to accomplish my task:
package main
import (
"encoding/json"
"fmt"
"log"
"reflect"
"strings"
"unicode"
)
type Response struct {
Id int `json:"id"`
FromId int `json:"from_id"`
Attachments []Attachment
}
type Attachment struct {
Type string
Fields map[string]interface{}
}
func (this *Attachment) UnmarshalJSON(b []byte) (err error) {
type innerAttachment struct {
Type string
Audio map[string]interface{}
Photo map[string]interface{}
}
inAt := innerAttachment{}
*this = Attachment{}
if err = json.Unmarshal(b, &inAt); err == nil {
this.Type = inAt.Type
a := []rune(inAt.Type)
a[0] = unicode.ToUpper(a[0])
v := reflect.ValueOf(inAt)
m := v.FieldByName(string(a)).Interface()
this.Fields = m.(map[string]interface{})
}
return
}
func main() {
encoded := `
{
"id": 123,
"from_id": 234,
"attachments": [
{
"type": "audio",
"audio": {
"artist": "Van Halen",
"title": "Eruption"
}
},
{
"type": "photo",
"photo": {
"id": 123,
"url": "http://someurl.com"
}
}
]
}
`
response := &Response{}
reader := strings.NewReader(encoded)
err := json.NewDecoder(reader).Decode(&response)
if err != nil {
log.Fatal(err)
}
for _, v := range response.Attachments {
fmt.Println(v.Type)
for key, value := range v.Fields {
fmt.Printf("%s => %s\n", key, value)
}
fmt.Println("")
}
}
Is my code OK or maybe there's more Go'ish way to unmarshal JSON provided above?