Tech Blog - Akihiro Suzuki

GoでHTTPルーターを自作する

January 03, 2022

トライ木

Go には net/http パッケージが標準で備わっており手軽に HTTP サーバーを構築することが出来ます。

package main

import (
  "fmt"
  "net/http"
)

func main() {
  http.HandleFunc("/", hello)
  http.ListenAndServe(":8080", nil)
}

func hello(w http.ResponseWriter, r *http.Request) {
  fmt.Fprint(w, "Hello World!")
}

なんとこれだけ。

run すれば HTTP サーバーが立ち上がります。

go run main.go

便利ですね〜

しかし、実用には少しばかり機能が足りません。

私が思う net/http に足りない機能

  • 正規表現による path の定義が出来ない
  • path parameters を備えてない
  • path の完全一致のみのルーティングを備えていない

3 つ目は何を言っているのかというと、 net/httpのルーティングは前方一致なので、上の例だと/以外にも/hogeなどもルーティングされてしまうのです。

path の完全一致のみのルーティングを備えていない

うーん、、、これではあまりにも不便ですよね。。。

機能が足りないなら作ればいいじゃない

ということで、今回は Go で HTTP ルーターを自作したので、ご紹介。

GitHub のレポジトリは以下。

https://github.com/akhrszk/gorouter

どのように実現されているのか?

宣言されたルーティグ情報を、トライ木(trie)と呼ばれるツリー構造で保持しており、高速なパスマッチングを実現しています。

以前、二分探索木を JavaScript で実装しましたが、あのイメージです。

gorouter では、以下の機能を実現しています。

  • path の完全一致のルーティング
  • path parameters を取得
  • 正規表現による path の宣言

使用方法

Handler 関数は標準のnet/httpw http.ResponseWriter r *http.Requestをそれぞれ第1引数、第2引数で受け取るのに加え、gorouter では第3引数で path parameters を受け取ります。

package main

import (
  "fmt"
  "net/http"

  "github.com/akhrszk/gorouter"
)

func hello(w http.ResponseWriter, r *http.Request, params gorouter.Params) {
  name := params["name"]
  fmt.Fprintf(w, "Hello, %s!", name)
}

func main() {
  r := gorouter.New()
  r.Get("/hello/:name", hello)
  http.ListenAndServe(:3000, r)
}

以上、gorouterの紹介でした!


profile

鈴木 章弘 (Suzuki Akihiro)
バックエンドエンジニア(TypeScript & マイクロサービス)
profile