Go 言語 Webフレームワークはこれを使おう 2016年12月版

この記事は Qiita Advent Calendar 2016 Go (その2) 10日目の記事です。

Go言語の Web アプリケーションフレームワーク (以下、Web フレームワーク) は、群雄割拠の時代を経てわずかばかりまとまってきた印象があります。今回、Go言語の Web フレームワーク を選定するさいの参考になればと思い、あらためていくつかのフレームワークの特長や最近の動向をまとめました。

結論

現時点では iris または Echo の選択をおすすめします。

追記 2016-12-10 17:13

結論を、Echo をおすすめ、と訂正いたします。

記事を公開したあとで、iris はレポジトリの運営方針などに問題があるというご意見を見かけました。あわせて、以下のリソースをご紹介いただきました。

b.hatena.ne.jp

参照先 URL が直接投稿できない模様です*1。上記の URL 経由で掲載しておきます。

ご指摘のとおり、残念ながら iris は現状ではおすすめできないパッケージとなってしまっているようです。最近の動向、、といいつつこの点を抑えられいなかった点についてとても反省しています。いちど公開してしまった内容なので、紹介記事は削除せずに追記という形式で情報を更新いたしました。ご意見くださり誠にありがとうございました。

追記ここまで

選定と推薦の根拠

  • 主観
  • GitHub Trending, Star, Issue
  • プロダクトでの使用経験 (Gin, Echo)

現在、株式会社ユーリエ のプロダクト eurie Desk 開発における主たる言語として Go言語を利用しています。プロダクション環境での利用をつうじて得た知見を判断材料の1つにしています。

今回の候補一覧

他にも伝統的なパッケージがいくつか存在しますが、開発の状況やその他理由により選外としました。

前提として RESTful API (以下、REST API) の実装に採用することを念頭に置いていますので、HTML Template Engine に関連した情報は登場しません。掲載していないものがよくないというわけではありませんのであしからず。

Gin

github.com

Gin は古くから人気のあったパッケージの1つです。一時期開発が停滞していましたが Contributor 増員後はそこそこの頻度で開発が続いています。Microframework ながらかゆいところに手が届く実装で、Echo や iris の機能開発の参考にされていた印象があります。

REST API の Request Body を Struct に Bind するさい、Struct に定義した binding タグ の内容にもとづき値の Validation を行うが特長です。

type User struct {
    Name  string `json:"name" binding:"required"`
    Age   uint   `json:"age" binding:"gte=0,lte=130"`
    Email string `json:"email" binding:"required,email"`
}

上記の Struct を以下のように利用します。

func PostUser(c *gin.Context) {

    user := new(model.User)
    if err := c.BindJSON(user); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"message": err.Error()})
        return
    }

    c.JSON(http.StatusCreated, gin.H{"status": "ok"})
}

以下の JSON を POST で送付します。

{
    "name" : "Your Name.",
    "age": 30,
    "email": "invalid.com"
}

この場合 Email の書式が不正なため エラー "Key: 'User.Email' Error:Field validation for 'Email' failed on the 'email' tag" が生じます。

処理としては go-playground/validator を利用しているというシンプルなアプローチです。Gin を利用しない場合でもこの実装は参考になると思います。

// https://github.com/gin-gonic/gin/blob/master/binding/json.go#L19
func (jsonBinding) Bind(req *http.Request, obj interface{}) error {
    decoder := json.NewDecoder(req.Body)
    if err := decoder.Decode(obj); err != nil {
        return err
    }
    return validate(obj)
}

Validation に関する補足

ところで、Struct の binding タグによる Validation を行う場合には、以下の課題があります。結論からいうと、ある程度の規模以上のアプリケーションではこの方法の採用はおすすめできません。

  • 可読性が悪い
  • タグは build 時に Check されないためミスのもとになる
    • go vet で検出する方法はあります*2
  • POST/PUT で Struct を共有する場合かつ Validation の内容が異なる場合、複数タグを付与して使い分けるなど更に可読性が悪くなる
    • 僕が以前取り入れていた方法*3はあまりよくありませんでした

Model の構造や Validation の要件がごく単純な場合には手軽に利用できます。

最近の動向

12月3日に v1.1 がリリースされています。

Gin は 僕が Go 楽しいと思ったきっかけの Product なので、今後も人気が続くといいなぁと思っています。

Echo

Echo は、Gin の開発停滞期に人気が急上昇した印象のある Web フレームワークです。公式サイトのドキュメントが詳しく、Web アプリの汎用的な課題を解決できるミドルウェアがバンドルされています。

echo.labstack.com

たとえば、Cross-Origin Resource Sharing の設定を行える CORS Middleware) や、Request Header に含まれる JWT を Parse する JWT Middleware などが便利なミドルウェアの一例です。

ミドルウェアに関する補足

ミドルウェアの実装と活用は Echo に限った話ではないのですが、ここで補足しておきます。典型的な汎用処理は、データベースのトランザクションの管理です。

const (
    TxKey = "Tx"
)

func TransactionHandler(db *sql.DB) echo.MiddlewareFunc {
    return func(next echo.HandlerFunc) echo.HandlerFunc {
        return echo.HandlerFunc(func(c echo.Context) error {
            tx, _ := db.Begin()

            c.Set(TxKey, tx) // echo.Context にトランザクションの pointer をセットして、後続の処理の中で取り出せるようにしています

            if err := next(c); err != nil {
                tx.Rollback() // このミドルウェア以後でエラーが発生した場合はロールバックします
                return err
            }
            helper.Logger.Debug("Transaction has been committed.")
            tx.Commit() // エラーが発生しなかった場合はコミットします

            return nil
        })
    }
}

実装したミドルウェアを、以下のようにセットします。

e := echo.New()
e.Use(middleware.TransactionHandler())

e.POST("/users", api.PostUser())
e.PUT("/users/:id", api.PutUser())

このようにしておくとすべてのエンドポイントが 1 Request = 1 Transaction で管理されます*4

ロギングや 認証周り、例外発生後の共通処理などをミドルウェアとして実装しておくとコアロジックの実装に集中できるようになります。

最近の動向

v3.0.0 がリリースされています*5Let's Encrypt との連係など、TLS 関係が強化されています。

v2 までは、valyala/fasthttp パッケージを取り込み高いベンチ—マークを誇っていたことでも知られていました。メジャーアップデートとなる v3 からは fasthttp への 依存が取り払われ、標準の net/http パッケージのみのサポートとなりました。プロジェクトをシンプルに保つことが目的とアナウンスされています *6

Echo には現時点で REST API を開発するに充分な機能が備わっており安定して利用できます。

iris

追記 2016-12-10 17:13

結論に追記したとおり、iris のおすすめは取り下げさせていただきます。以下は、参考情報としてご覧いただければと思います。

追記

github.com

iris は非常に開発が活発な Web フレームワークで、GitHub の Trending にもたびたび登場していた時期がありました。比較的後発ですがバージョンが 5.0 まであがっています。ベンチマーク最速をうたっている*7のが特長でしょうか。後発らしく (?) Go の v1.7 以上が動作要件です。

GitBook で書かれた丁寧なドキュメントが用意されていることも特長の1つです。

また、サンプル集が多く用意されています。

github.com

Echo も充分にドキュメントが揃っていますが、iris はさらに充実している印象です。このドキュメントに書かれているコードををひととおり動作させることで、いくつかの重要な要素技術 (例えば CORS や セキュリティに関する HTTP Header の仕様についてなど) についても触れることができます。そうした観点から、REST API を初めて実装してみようとされているかたにも iris はおすすめできるかも知れません。ただし日本語情報はほぼ皆無と言えますのでその点は気にとめておいてください。

最近の動向

上述のとおり、最新のバージョンは v5.0 です。v4系を LTS (Long-Term Support) として維持するようです。この手の Go のパッケージで LTS を宣言しているものはあまり見たことがないかも知れません。

また、Echo が v3 から依存関係を解消した fasthttp を iris は v4 から採用していることも動きとしては面白いと思います。

まとめ

今回取り上げた 3つの Web フレームワークはいずれも癖がなく使いやすいものです。もしも将来的に移行の必要が生じた場合でも、現実的なコストで行える程度だと考えています。いずれを選んでも宜しいと思いますが、結論で述べたとおり、ドキュメントの充実度や継続可能性も踏まえ今回は Echo と iris をおすすめ Web フレームワークとしました。

Go 言語のエコシステムは現在成長著しく、じつにさまざまな OSS パッケージが日々登場しています。Web フレームワークの勢力図が半年後にまたどのように変化しているか楽しみです。

推薦図書

和書で Go言語の基本文法を学びたいかたには下記をおすすめします。

改訂2版 基礎からわかる Go言語

改訂2版 基礎からわかる Go言語

洋書ですが次の書籍も評判がよいようです。

The Go Programming Language (Addison-Wesley Professional Computing Series)

The Go Programming Language (Addison-Wesley Professional Computing Series)