Golang Cafe #38 まとめ Gorilla web toolkit を試す。 その1

2014/07/13に開催された「Golang Cafe #38」についてのまとめです。

開催からかなり経ってしまいましたが、記録としてまとめておきます。


今回はGorilla is a web toolkitを試してみる会となりました。
Gorilla is a web toolkitとは何か、簡単言うと、Go言語でWeb系のプログラミングを行うのにルーティングやらクッキー(セッション)の処理やらを上手くやってくれるツールキットのようです。フレームワームでは無いようです。


有名所でいうと最近何かと話題のDockerで使われていたり(確認した当時では)、GoogleI/OのGo言語のcodelaboで使用されていたりなど、Go言語ではスタンダードになりつつあるパッケージのようです。


Gorilla is a web toolkitには

  • gorilla/context
  • gorilla/mux
  • gorilla/reverse
  • gorilla/rpc
  • gorilla/schema
  • gorilla/securecookie
  • gorilla/sessions

のパッケージがあるようです。


その中から、今回はgorilla/muxをみてみました。

gorilla/mux

本家の説明はこちらのページ
Go言語でHTTPサーバーを建てる場合には、

http.Handle("/foo", fooHandler)

http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
})

http.ListenAndServe(":8080", nil)

このような感じでルーティングと対応するハンドラを定義します。
あくまでURLとハンドラを結びつけているだけで、GETだろうが、POSTだろうが、パラメータがついていようが、単純にハンドラが呼ばれます。必要であればハンドラ内で処理するというのが比較的一般的なやり方のようです。
これらのような判定処理などやより高度な処理をハンドラが呼ばれれまでにやってしまおうというのがgorilla/muxパッケージです。

まずはインストール。

$ go get github.com/gorilla/mux

ホストやメソッドやヘッダやいろいろな条件でハンドラの呼び出しを制限できるようなのですが、詳細はドキュメントを確認してもらうとして、少しだけサンプルを残しておきます。

func main() {
    r := mux.NewRouter()
    r.HandleFunc("/products/{key}", ProductsHandler)
    r.HandleFunc("/article/{category}", ArticlesCategoryHandler)
    // 正規表現にマッチしない場合は404
    // 最後の/がないと直前のパラメータはなかったことになる
    r.HandleFunc("/article/{category}/{id:[0-9]+}/", ArticleHandler).Methods("GET")

    // 404のときのハンドラ
    r.NotFoundHandler = http.HandlerFunc(NotFoundHandler)

    http.Handle("/", r)

    http.ListenAndServe(":8080", nil)
}

func ProductsHandler(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)

    for k, v := range vars {
        fmt.Println(k, v)
    }

    w.Write([]byte("ProductsHandler"))
}

func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)

    for k, v := range vars {
        fmt.Println(k, v)
    }

    w.Write([]byte("ArticlesCategoryHandler"))
}

func ArticleHandler(w http.ResponseWriter, r *http.Request) {
    vars := mux.Vars(r)

    for k, v := range vars {
        fmt.Println(k, v)
    }

    w.Write([]byte("ArticleHandleer"))
}

func NotFoundHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Println(r)

    http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
}

気をつけておきたいのは、アクセスしたURLがルーティングに定義されていない場合は404になります。また定義するパスの最後に/を必ず付けておかないとダメなようです。
ルーティングが定義されていない場合は、デフォルトのハンドラが定義されているようなのですが、

r := mux.NewRouter()
r.NotFoundHandler = http.HandlerFunc(NotFoundHandler)

のようにすれば独自に404用のハンドラを定義できるようです。