· encoding/json golang Go言語

構造体にフィールドを追加しないで、JSONに動的にフィールドを追加したい #golang

  • このエントリーをはてなブックマークに追加

はじめに

JSONを返したい場合、定義済みの構造体に対してjson.Marshalとかして、JSONにしていたのですが、下記のBook構造体の例だと、返せるフィールドはTitle,Authorだけになってしまいます。

type Book struct {
    Title  string
    Author string
}

response, _ := json.Marshal(book)
fmt.Fprintf(w, string(response))

それ以外のフィールドも動的に追加するにはどうしたらか調べたので書いておこうかと思います。

方法

基本的には、stackoverflowに書いてありますので、参考くださいなんですが、下記のような感じです。

type Book struct {
    Title  string
    Author string
}

type FakeBook Book

func (b Book) MarshalJSON() ([]byte, error) {
    return json.Marshal(struct {
        FakeBook
        Genre string
    }{
        FakeBook: FakeBook(b),
        Genre:    "Satire",
    })
}

このように、Book構造体に対して、Mashalerインターフェースを実装することで、フィールドを追加することができます。

結果は以下のとおり。

{
  "Title": "Catch-22",
  "Author": "Joseph Heller",
  "Genre": "Satire"
}

仕組みとしては(簡単に)

この場合、BookMarshalerインターフェースを実装したことになります。(Marshalerインターフェース)

これによって、Marshalerインターフェースを実装しているならmarshalerEncoderがコールされ、MarshalJSONがコールされます。

配列の各要素に追加したい場合も同様で、

つまり次のような場合、

type Book struct {
    Title   string
    Authors []Author
}

type Author struct {
    Name  string
    Email string
}

Author構造体にMashalerインターフェースを実装してあげればいいだけです。

func (b Author) MarshalJSON() ([]byte, error) {
    return json.Marshal(struct {
        FakeAuthor
        Genre string
    }{
        FakeAuthor: FakeAuthor(b),
        Genre:      "Satire",
    })
}

Playground: http://play.golang.org/p/tZEaLTt7Fc

結果は次のようになります。

{
  "Title": "Catch-22",
  "Authors": [
    {
      "Name": "Joseph",
      "Email": "abc@xxx.com",
      "Genre": "Satire"
    },
    {
      "Name": "Heller",
      "Email": "dec@yyy.com",
      "Genre": "Satire"
    }
  ]
}

以上です。

  • このエントリーをはてなブックマークに追加
  • LinkedIn
  • Tumblr
  • Reddit
  • Google+
  • Pinterest
  • Pocket