Unmarshaling dynamic JSON 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, &amp;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 := &amp;Response{}
    reader := strings.NewReader(encoded)
    err := json.NewDecoder(reader).Decode(&amp;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 =&gt; %s\n", key, value)
        }
        fmt.Println("")
    }
}


Is my code OK or maybe there's more Go'ish way to unmarshal JSON provided above?
I would not implement method UnmarshalJSON as it is not really necessary. Instead, I would create Audio and Photo types and put them as fields into Attachment type. It would be easier to reference data as field than get it as a value from map.

package main

import (
    "encoding/json"
    "fmt"
    "log"
    "strings"
)

type Response struct {
    Id          int `json:"id"`
    FromId      int `json:"from_id"`
    Attachments []Attachment
}

type Audio struct {
    Artist string `json:"artist"`
    Title  string `json:"title"`
}

type Photo struct {
    Id  int    `json:"id"`
    Url string `json:"url"`
}

type Attachment struct {
    Type  string
    Audio `json:"audio"`
    Photo `json:"photo"`
}

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 := &amp;Response{}
    reader := strings.NewReader(encoded)
    err := json.NewDecoder(reader).Decode(&amp;response)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(response)
}