【Golang】jsonのomitemptyタグについて

# はじめに

構造体をJSONに変換したときに、不要なフィールドを除外したい
valueに``null``を入れるのではなく、そもそもkeyもvalueも除外したい

そのような時に使う``omitempty``タグなるものがあるが、いくつかハマりポイントがあったので備忘録として残す

# 基本的な使い方

以下のような構造体がある

```golang
type Player struct {
  Name     string  `json:"name"`
  Age      int     `json:"age,omitempty"`
  Weight   int     `json:"weight"`
}
```

これを以下のような形でJSONに変換する

```golang
player1 := Player{
  Name: "Alice",
}

hogehoge, err := json.Marshal(player1)

// このようにして生成されるJSONは以下の通り
// {
//   "name": "Alice",
//   "weight": 0
// }
```

- ``omitempty``タグをつけていない``weight``フィールドには初期値（？）の``0``が勝手に入っている
- タグをつけた``age``フィールドは無視されている


しかし、公式Docによると、このように``omitempty``タグをつけることで無視できるフィールドの型は決まっている

> The "omitempty" option specifies that the field should be omitted from the encoding if the field has an empty value, defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string.

→bool型のfalse、int型などの0、nilポインタ、nilインターフェース、空のarray・slice・map、空文字あたりが``omitempty``タグを使えるらしい

# 構造体を無視したい

では、以下のような``Player``のフィールドにある``Item``構造体を無視したい場合はどうすれば良いか？

```golang
type Player struct {
  Name     string  `json:"name"`
  Age      int     `json:"age,omitempty"`
  Weight   int     `json:"weight"`
  Item     Item    `json:"item,omitempty"`
}

type Item struct {
  Name     string  `json:"name"`
  Price    int     `json:"price"`
}
```

まず、素直に``Item``に``omitempty``タグをつけてみると、

```golang
player1 := Player{
  Name: "Alice",
}

hogehoge, err := json.Marshal(player1)

// このようにして生成されるJSONは以下の通り
// {
//   "name": "Alice",
//   "weight": 0,
//   "item": null,
// }
```

上記のように、``item``は無視されず、``null``が入ってしまう

これを回避するには、ポインタを使えば良い

```golang
type Player struct {
  Name     string  `json:"name"`
  Age      int     `json:"age,omitempty"`
  Weight   int     `json:"weight"`
  Item     *Item   `json:"item,omitempty"`
}
```

``omitempty``タグでnilポインタは無視することができるので、

```golang
player1 := Player{
  Name: "Alice",
}

hogehoge, err := json.Marshal(player1)

// このようにして生成されるJSONは以下の通り
// {
//   "name": "Alice",
//   "weight": 0
// }
```

# ``null``は無視したいけど``0``は許可したい

例えば、int型のフィールドで、``null``の場合はJSONに含めたくないけど、``0``の場合は含めたいことがある

このような場合にもポインタ型が役立つ

```golang
type Player struct {
  Name     string  `json:"name"`
  Age      *int    `json:"age,omitempty"`
  Weight   int     `json:"weight,omitempty"`
}

zero := 0

player1 := Player{
  Name:   "Alice",
  Age:    &zero,
  Weight: 0,
}

hogehoge, err := json.Marshal(player1)

// このようにして生成されるJSONは以下の通り
// {
//   "name": "Alice",
//   "age": 0
// }
```

# ``omitempty``タグのつけかたに注意！！

これは、もしかしたら超基本的なことなのかもしれないが、以下のように記述すると``omitempty``が上手く働かない

```golang
type Player struct {
  Name     string  `json:"name"`
  Age      int     `json:"age, omitempty"`
  Weight   int     `json:"weight"`
}
```

`` `json:"age, omitempty"` ``
この部分の``,``と``omitempty``の間に半角スペースがあることが悪さをしているらしい
なので、正しくは以下の通り

```golang
type Player struct {
  Name     string  `json:"name"`
  Age      int     `json:"age,omitempty"`
  Weight   int     `json:"weight"`
}
```

# さいごに

``omitempty``に限らず、しっかりと公式Doc読むの大事！
ポインタが便利

# 参考
- [json - The Go Programming Language](https://golang.org/pkg/encoding/json/#Marshal)
- [Structをomitemptyする方法 - Qiita](https://qiita.com/taroshin/items/59e62d8ec852c5f84bc1)
- [Go's "omitempty" explained](https://www.sohamkamani.com/golang/omitempty/#values-that-cannot-be-omitted)