先日のgolang.tokyo #7で自社パッケージの紹介LT大会にてLTでjson2structと言うパッケージの紹介をさせていただきました。
細かい使い方や既存の同様のツールとの差異について書いていきたいと思います。
ツールの概要
GolangではJSONからデータを取得する際にあらかじめstructの定義をしておくことがありますが、その際に下記のようにタグ等など設定しなくてはならず、手間がかかってしまうのが面倒くさい。 また外部のAPI等でJSONの形式が複雑な場合その定義はより手間がかかってしまう。
{"url": "http://blog.yudppp.com", "text": "Hello:)", "status": 1}
type Blog struct {
Status int `json:"status"`
Text string `json:"text"`
URL string `json:"url"`
}
それらを解決するために、JSONからGolangのstructの形式に変換するツールは幾つか既に存在しています・。
私はこれらのツールを使っていたのですが、実際に使う際に使いにくいポイントがあったので自分で作成しました。
json-to-go
json-to-goはサイト上でJSONをstructに変換してくれるツールです。
https://mholt.github.io/json-to-go/
こちらの実行結果を見ていくと普段自分が書かないstructのnestや[]structといったものができてしまい、個人的には実用的でないと判断し使うことをやめました。
またJavaScript製でgofmtがされていないものが出力されます。
input
{"url": "http://blog.yudppp.com", "text": "Hello:)", "status": 1, "categories": [{"name": "golang"}]}
output
type AutoGenerated struct {
URL string `json:"url"`
Text string `json:"text"`
Status int `json:"status"`
Categories []struct {
Name string `json:"name"`
} `json:"categories"`
}
gojson
https://github.com/ChimeraCoder/gojson
gojsonも同様のツールでcliを用いて、JSONのinputに対してstructを吐き出します。defaultではstructがnestするのですが、-subStruct
のオプションを設定することによって別のstructに分けることができます。
ただし生成されるサブストラクト名がBlog_sub1
という名前でこのまま使いたくなくrenameする必要がありました。
$ echo '{"url": "http://blog.yudppp.com", "text": "Hello:)", "status": 1, "categories": [{"name": "golang"}]}' \
| gojson -name Blog
package main
type Blog struct {
Categories []struct {
Name string `json:"name"`
} `json:"categories"`
Status int64 `json:"status"`
Text string `json:"text"`
URL string `json:"url"`
}
$ echo '{"url": "http://blog.yudppp.com", "text": "Hello:)", "status": 1, "categories": [{"name": "golang"}]}' \
| gojson -name Blog -subStruct
package main
type Blog struct {
Categories []Blog_sub1 `json:"categories"`
Status int64 `json:"status"`
Text string `json:"text"`
URL string `json:"url"`
}
type Blog_sub1 struct {
Name string `json:"name"`
}
またWeb上で確認できるものがなく、CLIで確認する方法しかありませんでした。
json2struct
これらを受けてjson2structを作成しました。
json2structを使うと先ほどのJSONが下記のようになります
$ echo '{"url": "http://blog.yudppp.com", "text": "Hello:)", "status": 1, "categories": [{"name": "golang"}]}' \
| json2struct -name Blog
type Blog struct {
Categories []BlogCategory `json:"categories"`
Status int `json:"status"`
Text string `json:"text"`
URL string `json:"url"`
}
type BlogCategory struct {
Name string `json:"name"`
}
gojsonではBlog_sub1
だったものがBlogCategory
に変わっています。 こちらでポイントなのがプロパティ名がCategories
と複数形だったものを配列だったので単数形にCategory
と変換したものともとのstruct名であるBlog
と足しあわせてBlogCategory
としています。(外部のパッケージ使っただけですが)
またサブストラクトの命名をオプションで色々変更ができるようにしていて、元のstruct名を引き継ぐのが冗長的で嫌いという人には-short
のOptionをつけるとCategory
というstruct名になったり、suffixにResponseをつけたいというのであれば-suffix Response
とするとそれぞれBlogResponse
,BlogCategoryResponse
となるようになります。
細かなOptionについては下記のようになっています。 最新はREADMEを参照してください。
option | description |
---|---|
name | メインのストラクト名を指定する |
prefix | ストラクトのprefixを指定する |
suffix | ストラクトのsuffixを指定する |
short | サブストラクトの命名を簡易にする |
local | local変数にする |
omitempty | omitemptyのオプションをつける |
example | example tagをつける(後述します) |
欲しいオプション等ありましたら気軽に実装していきたいと思いますのでissueとかに書いていただけたらと思います。
playgroundについて
こちらで簡単にWeb上でjson2structを利用することができます。 またオプションの値をWeb上で変えられるので出力結果を見ながらオプションの変更をすることができます。
技術的にはGopherJSとvectyを使っています。 GopherJSはGoで書かれたコードをJavaScriptに変換してくれるもので、vectyは語弊があるかもしれませんが簡単に言うとGopherJSをReact風にかけるもので、これにより簡単にGopherJSを導入することができました。
example tagについて
-example
をつけるとexampleタグが自動でつくようになります。 このexampleタグを利用するとJSONのサンプルの値を簡単に入れれるようになります。(完全に元のJSONに戻るもので現状ありません(配列の扱いが辛い))
package main
import (
"fmt"
"github.com/yudppp/structs"
)
type Blog struct {
Categories []BlogCategory `json:"categories"`
Status int `json:"status" example:"1"`
Text string `json:"text" example:"Hello:)"`
URL string `json:"url" example:"http://blog.yudppp.com"`
}
type BlogCategory struct {
Name string `json:"name" example:"golang"`
}
func main() {
blog := structs.NewExample(Blog{}).(Blog)
fmt.Println(blog.Text) # -> Hello:)
fmt.Println(blog.Categories[0].Name) # -> golang
}
このように簡単にサンプル用の値を入れることができるのでテストや開発時のモックAPI、ドキュメント作成時に利用していければと思っています。
まとめ
ストラクトを分けたくてストラクト名をいい感じにしたいならjson2structがオススメです。
絶賛リファクタリング中なのでCLIのインターフェースは変えないが中身が雑すぎて恥ずかしいので絶対に見ないでほしい。
は引き続きお願いします。[Github]
将来直したいこと
- プロパティ名がアルファベット順になっているので元のJSONの順番になるように合わせたい
- GopherJSでクリップボードにコピーしたい
- example tagを完璧に元のJSONに戻せるようにしたい。
- 出力されるstruct名が被ってしまう場合があるのでその時の対処を考える。(Imageストラクトがいろんなストラクトに含まれている場合など)