golang+kocha を使ってみて
簡単な Web アプリケーションを作る機会があったので、前々から興味あった golang で作ってみた。
当初 revel で作ろうとしたが、マイグレーションが自前実装?だったりトランザクションをコントローラに実装する点が個人的に気持ちが悪くて止めた。
RoR っぽいし和製という単純な理由で kocha を採用。
やったこと・感じたことを書いていく。
環境
情報が少ない
golang の Web フレームワーク全体に言えることかも知れないが、とにかく少ない。
和製だからこそ日本語の情報が多いのかなと思ったが甘かった。ドキュメント自体も英語。
アプリケーション固有の設定
ドキュメントのデータベース設定に関する項で、「The Twelve-Factor App」にインスパイアされたと書かれており、環境変数を使って設定を行う。
参照: Model | Kocha web application framework for Go
当初、アプリケーション固有の設定をどこに記述して良いか分からず、設定ファイルを用意して読み込ませていた。
The Twelve-Factor App を知ってからは環境変数に記述し、kocha.Getenv
で取得するようにした。
データベースのデフォルト文字コードを utf8(mb4) にしてはならない
デフォルトのストレージエンジンを InnoDB のまま、デフォルトの文字コードを utf8 などにするとマイグレーションが実施されない。
kocha のマイグレーションは、バージョンを管理する為に schema_migration テーブルを作成するのだが、
このテーブルの主キーは VARCHAR(255) であり、InnoDB+utf8 だと 767 byte を越えてインデックスを貼れずにエラーとなる。
ROW_FORMAT を DYNAMIC にして対応しようかと思ったが、SQL がハードコーディングされていたので無理そうだった。
参照: https://github.com/naoina/kocha/blob/37ac3fb2dcdc22508c647d39cd750da6a53fef1d/db.go#L126
ちなみに、schema_migration の作成を失敗しても kocha 上ではエラーならないので注意。
マイグレーションの書き方
ドキュメントを見ると、雛形の生成で話が終わっていてサンプルが無い。
テーブルを作成するのであれば、恐らく genmai で CreateTable を実行するのがベストだと思う。
参照: https://github.com/gurisugi/kocha-sample/blob/master/scripts/create_table.go#L23
今回は細かく設定したかったので SQL で書いた。
package migration import "github.com/naoina/genmai" func (m *Migration) Up_20150806072506_CreateUsersTable(tx *genmai.DB) { if _, err := tx.DB().Exec(` CREATE TABLE users ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, name VARCHAR(100) NOT NULL, created_at DATETIME, PRIMARY KEY (id) ) ENGINE = InnoDB DEFAULT CHARSET 'utf8mb4' `); err != nil { panic(err) } } func (m *Migration) Down_20150806072506_CreateUsersTable(tx *genmai.DB) { if _, err := tx.DB().Exec(`DROP TABLE users`); err != nil { panic(err) } }
ORM で細かいことは出来ない
kocha では genmai という ORM が使われているが、細かい事をするなら内部で使用されている database/sql
を取り出して使う必要がある。
詳しい理由は、次の参考サイトに分かり易く書かれている。
もちろんgenmaiにもJOINをビルドするAPIはあるんだけど、ビルドされるフィールドの指定が暗黙的に"テーブル名".*みたいになるため、JOINで持ってきたテーブルのカラムを参照するようなことが出来ない。
まさしくその通り。
現状の ORM で開発は難しく、ほぼ database/sql
を使って書いてた。
共通処理
例えば revel ではページを表示する際、以下のレスポンスヘッダを返す。
X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block X-Content-Type-Options: nosniff
これを kocha でも実現するなら、どこに記述するのかが分からなかった。
色々と考えた結果、Middleware を使えばうまくいきそうだったので試したところうまくいった。
▼レスポンスヘッダ出力例
// config/app.go // ...[略] type RequestMiddleware struct{} func (m *RequestMiddleware) Process(app *kocha.Application, c *kocha.Context, next func() error) (err error) { header := c.Response.Header() header.Set("X-Frame-Options", "SAMEORIGIN") header.Set("X-XSS-Protection", "1; mode=block") header.Set("X-Content-Type-Options", "nosniff") return next() } // ...[略] var ( AppConfig = &kocha.Config{ // ...[略] // Middlewares. Middlewares: []kocha.Middleware{ &kocha.RequestLoggingMiddleware{}, &kocha.PanicRecoverMiddleware{}, &kocha.FormMiddleware{}, &kocha.SessionMiddleware{ // ...[略] }, &kocha.FlashMiddleware{}, &RequestMiddleware{}, // --> 追加 &kocha.DispatchMiddleware{}, } } )
同様に認証が必要な場合も Middleware を用意すると良い。
今回は Basic 認証を掛けたかったので、専用の Middleware を用意した。
ページネーションとかそういった類の物はない
kocha 側では用意されていない。
必要なら世に出回っている golang 製のページネーションを持ってくる必要がある。
今のうちに使い易いページネーションを作っておくと重宝されるかもしれない。
まとめにならないまとめ
作成した Web アプリケーションは元気よく OpenShift 上で動いている。
今回初めて golang で開発をしたが、全体的に Web に関して未成熟な印象を受けた。
これからどんどん発展していくのだろうから、追い続けたいところ。
kocha に関しては、開発を始める上でとても入り易かった。
願わくば日本語のドキュメントが充実するととても嬉しい。