はじめに
Go 1.4 にて導入されたgo generateコマンドを使って、JSONファイルからソースコードを自動生成してみます。
今回は、JSONファイルに定義されたWebアプリケーションのルーティング情報をもとに、ルーターのプログラムが記載された単純なソースコードを生成してみます。
今回の手順で作成したソースコードは、こちらのリポジトリに格納しています。
今回、ルーターにはgorilla/muxを使用しています。
JSONファイルからソースコードを生成するコマンドの作成
まずは、以下のようなルーティング情報が記載されているJSONファイルを読み込み、ルーターのプログラムが記載されたソースコードを生成するコマンドを作成します。
[
{"method": "GET", "path": "/", "handler": "topHandler"},
{"method": "GET", "path": "/users", "handler": "usersIndexHandler"},
...
]
cmd/gen-router/main.go
package main
import (
"bytes"
"encoding/json"
"flag"
"io/ioutil"
"text/template"
)
const strTmpl = `// generated by gen-router; DO NOT EDIT
package main
import "github.com/gorilla/mux"
func newRouter() *mux.Router {
r := mux.NewRouter(){{range .}}
r.HandleFunc("{{.Path}}", {{.Handler}}).Methods("{{.Method}}"){{end}}
return r
}
`
type route struct {
Method string
Path string
Handler string
}
func main() {
inPath := flag.String("i", "", "input file path")
outPath := flag.String("o", "", "output file path")
flag.Parse()
in, err := ioutil.ReadFile(*inPath)
if err != nil {
panic(err)
}
var routes []route
if err := json.Unmarshal(in, &routes); err != nil {
panic(err)
}
tmpl, err := template.New("router").Parse(strTmpl)
if err != nil {
panic(err)
}
bf := new(bytes.Buffer)
if err := tmpl.Execute(bf, routes); err != nil {
panic(err)
}
if err := ioutil.WriteFile(*outPath, bf.Bytes(), 0644); err != nil {
panic(err)
}
}
上記プログラムの作成後、以下コマンドを実行し、ローカルマシンへgen-router
コマンドをインストールします。
$ go install ./cmd/gen-router
JSONファイルの作成
ルーティング情報を記載したJSONファイルを、以下の通り作成します。
routes.json
[
{"method": "GET", "path": "/", "handler": "topHandler"},
{"method": "GET", "path": "/users", "handler": "usersIndexHandler"},
{"method": "GET", "path": "/users/{id}", "handler": "usersShowHandler"},
{"method": "POST", "path": "/users", "handler": "usersCreateHandler"}
]
メインプログラムの作成
メインプログラムを以下の通り作成します。このプログラムは、go generate
コマンドで生成されるルーターを使用します。また、このソースコード上に、go generate
コマンド実行時の処理を定義した、//go:generate
で始まるコメントを記載します。
package main
import (
"fmt"
"net/http"
)
func topHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "topHandler")
}
func usersIndexHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "usersIndexHandler")
}
func usersShowHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "usersShowHandler")
}
func usersCreateHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "usersCreateHandler")
}
//go:generate gen-router -i routes.json -o router.go
func main() {
http.Handle("/", newRouter())
if err := http.ListenAndServe(":8080", nil); err != nil {
panic(err)
}
}
go generate コマンドの実行
以下の通り、go generate
コマンドを実行します。
$ go generate
以下の内容が記載されたrouter.go
ファイルが生成されたことを確認します。
// generated by gen-router; DO NOT EDIT
package main
import "github.com/gorilla/mux"
func newRouter() *mux.Router {
r := mux.NewRouter()
r.HandleFunc("/", topHandler).Methods("GET")
r.HandleFunc("/users", usersIndexHandler).Methods("GET")
r.HandleFunc("/users/{id}", usersShowHandler).Methods("GET")
r.HandleFunc("/users", usersCreateHandler).Methods("POST")
return r
}
動作確認
プログラムを実行し、ルーティング処理がJSONファイルの定義通りに実施されることを確認します。
$ go run main.go router.go
$ curl -XGET localhost:8080/
topHandler
$ curl -XGET localhost:8080/users
usersIndexHandler
$ curl -XGET localhost:8080/users/1
usersShowHandler
$ curl -XPOST localhost:8080/users
usersCreateHandler
おわりに
今回のサンプルは非常に単純なものでしたが、go generate
コマンドを有効活用することで、ソフトウェア開発作業を効率化させられることと思います。なお、JSONファイルからGo言語のソースコードを自動生成しているプロジェクトとして、stripe/aws-goがあります。