最近REST APIを作るためにGoを使っていますが、きれいにデータをJSONに変換するために少し苦労していました。
ほとんどのチュートリアルや記事では、静的なstruct
とタグを使ってJSONを返す方法について解説しています。
type User struct {
ID int `json:"id"`
Email string `json:"email"`
HideEmail bool `json:"hide_email"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
user := User{
ID: 1, Email: "x@example.com", FirstName: "Foo", LastName: "Bar",HideEmail: true
}
data, err := json.Marshal(user)
確かに便利ではありますが、返すデータを動的に選ぶこともかなり多いと思います。
例えばユーザがログインしているかどうか、プライバシー設定がどうなっているか、たくさん
の条件が入ってくると思います。
そういった場合は、毎回if
文などでデータを生成していくのも少し冗長すぎると思ったので、そのためのライブラリを作ってみました。
例として、以上の例のstruct
をsnake_case
に変えて、HideEmail
がtrue
だった場合はEmail
をJSONで返したくないとしたら、次のようなコードにできます。
userSerializer := structomap.New().
UseSnakeCase().
Pick("ID", "Email", "FirstName", "LastName").
Omit("HideEmail").
OmitIf(func(u interface{}) bool {
return u.(User).HideEmail
}, "Email")
一度これを作ったら、あとは
userSerializer.Transform(user)
でmap[string]interface{}
として欲しい結果が返ってくるので、それをjson.Encode
に渡せば終わりです。この方法を使うと、配列とスライスもそのまま使えるので、[]User
型の変数をuserSerializer.TransformArray
に渡せば、同じロジックで変換された[]map[string]interface{}
が返ってきます。
詳細についてはプロジェクトのページをご覧ください。