✉️

Goのルーターライブラリはnet/httpと互換性のあるものに

2022/06/26に公開

Goは標準ライブラリが充実しているので、基本的には3rd partyのライブラリを使わずに標準ライブラリを使うべきということはよく言われていることです。

しかし標準ライブラリのhttp.HandleFuncの第1引数のpattern変数に渡せるパターンは非常に貧弱で、しかもURLから変数を受け取ることもできません。

例えば/user/11というURLがあれば、/user/の後は数値だけが有効で、その数値を関数の中で簡単に取得できるような仕組みが欲しいと思う人が多いと思いますが、Goの標準ライブラリではいずれもできません(もちろんr *http.Request.URLからURLを受け取って処理を都度書けばできますが)。

数値しか受け取らないようにするのは自分で実装すればできますが、困るのは関数の中でURLの一部を渡す仕組みです。標準ライブラリの関数のインタフェースは以下のようになっています。

http.HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))

現在ではcontextパッケージがあり、http.Request.Context()があるので、context.WithValueを使用することでリクエスト毎に情報を付与することが可能です。

しかしhttp.Request.Context()が入ったのはGo 1.7からです。それより前から作られていたライブラリでは互換性のために独自インタフェースだったり、独自Contextを利用していたりと、混沌としていました。

Go自体が互換性を非常に重視する言語であることから、各種ライブラリも互換性を壊すことはあまりありません。なのでGo 1.7のリリースからかなり時間が経った今でもnet/httpと互換性のないライブラリが広く使われてしまっている現状です。

とりあえず新規で書くコードについては古いコードを引きずる必要はないと思うので以下のライブラリのように互換性があるものを使うことをおすすめします。

https://github.com/go-chi/chi

実はGoの場合、もう1つ問題があります。Goは正規表現を扱う標準ライブラリのregexpはパフォーマンスが他の言語より悪いことが多く、ルーターで使われるような単純な正規表現ではほぼ間違いなくパフォーマンスは低いです。なのでパフォーマンスを気にするならルーターライブラリを選ぶ際にregexpを使っているかどうか確認するのがおすすめです。先程紹介したchiは使用していないのでパフォーマンスも高く、おすすめできます。

Discussion