golangのstructでjsonのencodingのためのpropertyに omitempty
をつけた時の挙動とその使いどこを検討します。
omitemptyタグとは
https://golang.org/pkg/encoding/json/#Marshal には以下の用に記載されている。
The "omitempty" option specifies that the field should be omitted from the encoding if the field has an emptyvalue, defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string.
omitempty属性をつけたstructのjsonのpropertyははその値がfalse, 0, nilのpointer,長さが0の文字列と配列、sliceの時はjsonにencodeされるときに、propertyごと省略される
type Person struct { Name string `json:"name"` Age int64 `json:"age,omitempty"` //省略可能 }
上記hのようなstructを考える。
jon := Person { Name: "Jon", Age: 20 } // jsonにencodeしたときのoutput /* { "name": "jon", "age" : 20 } */ taro := Person { Name: "taro", } // jsonにencodeしたときのoutput /* { "name": "taro" } */
jsonにencodeしたときに omitempty
属性をつけておくとstructのinstance化のときに指定したなかったkeyについてはencodeしたjson文字列のpropertyとして含めない(省略される)。
ここまでは一般的なgoのencoding/jsonに関する知識。
ではこのomitemptyを実際のプロジェクトに使うときの注意点について検討する
omitemptyの使い所の検討
使い所はどこなのか。
omitempty
属性を使ういいところは必要ないstructのkeyをjsonにencodeしたときに自動で省略してくれるところであるので、例えば特定のリクエストのクエリパラメーターの値からjsonを生成して、別のAPIにPOSTするような動作を考えたときに、パラメータの有無によって生成するstructを返るなどの手間がいらなくなると思います。
具体的には以下のようなtokenと送信元をクエリパラメーターにタグとしてくっつけて、POSTした先でtokenと送信元をロギングするような挙動があったとします。
curl -i https:sample.com/user/1?token=hogehoge&from=yahoo.co.jp
こんなURLを叩くと以下のようなhandlerにリクエストが入ってくるとします。
package handler type Logging struct { Token string `json: "token"` From string `json: "from, omitempty"` } func SenderLogging(w http.ResponseWriter, r *http.Request) { values := r.URL.Query() token := values.Get("token") from := values.Get("from") // tokenもfromもクエリパラメーターがなければ空文字が入る。 logging := Logging{ Token: token, From: from, } b, _ := json.Marshal(&logging) // encodeされたjsonのbyte配列になる。 }
このとき from
が指定されたリクエストの時は from
に値が入ったjsonが生成され、from
が指定されない(直叩きされた)場合は from
のpropertyが省略され、ログにもfrom要素は記録されません。
from
の有無を見て、条件分岐等はする必要がありません。
omitempty
をうまく使うと、そこで差分を吸収してくれます。
懸念点
omitemptyの懸念点は上記にも記載しましたが false or "" or 0 or nil pointer
などそれ自体が意味を持っていそうな値の場合も omiempty
属性が付いていることでjson化したときにkeyは省略されてしまいます。
つまり、ともすると omitempty
属性をつけていることで意図するjsonが生成されないことが想定されます。
もし、認証のプロセスで必須のパラメータに omitempty
をつけていたら、何かの問題で空になってしまい、想定している正しいjsonが作られず、認証が通らない、ということが起きるかもしれません。
特に false
or 0
のようなそれ自体が意味を持ちそうな値の時ですら省略されてしまうのは気をつけないと、生成されるつもりだったということが起きかねないので注意が必要です。
まとめ
omitempty
は便利な属性だけど、使い方を見誤ると想定したjsonを生成しないということになるので注意が必要です。
ただし、使い勝手のいい機能なので、ちゃんと使っていきたい。