ルーティングとハンドラ
読了目安 約3分
http.ServeMux で複数のパスを捌き、ハンドラの 2 つの引数と http.Handler インターフェースの正体を読み解きます。
この章の目次
リクエストのパスとメソッドを見て、処理するハンドラを振り分けることをルーティングと呼びます。
ServeMux にルートを登録する
次の内容を main.go に保存してください。
Go 1.22 以降が前提です。
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("GET /hello", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello!")
})
mux.HandleFunc("GET /users/{id}", func(w http.ResponseWriter, r *http.Request) {
id := r.PathValue("id")
fmt.Fprintf(w, "ユーザー %s のページです\n", id)
})
mux.HandleFunc("POST /users", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "ユーザーを作成しました")
})
log.Fatal(http.ListenAndServe(":8080", mux))
}go run main.go で起動し、別のターミナルから叩きます。
curl http://localhost:8080/hello
curl http://localhost:8080/users/42
curl -X POST http://localhost:8080/userscurl -X POST はメソッドを POST に変える指定です(無指定なら GET)。
振り分けを担う ServeMux は、「パターンとハンドラの対応表」です。
前章の nil は内蔵の共有 ServeMux を指し、どこからでも書き換えられるため、以後は自作の mux を渡します。
パターンの書き方
"GET /users/{id}" のようなパターンは、メソッドとパスの 2 つの条件を表します。
"/hello" のようにメソッドを省くと、GET でも POST でも合致します。
{id} はパスパラメータで、その位置の任意の文字列に合致します。
/users/42 なら id に "42" が入り、ハンドラでは r.PathValue("id") で取り出せます。
メソッド付きパターンと
PathValueは Go 1.22 で入った機能です。 それ以前はパスの前方一致しかできず、この不足がフレームワークを使う理由の一つでした。
ハンドラの 2 つの引数
どのハンドラも同じ形です。
func(w http.ResponseWriter, r *http.Request)r *http.Request は、受信したリクエストの情報が詰まった struct へのポインタです。
Part 2 で見た HTTP の要素が、そのままフィールドです(r.Method、r.URL.Path、r.Header、r.Body)。
w http.ResponseWriter は、ステータスコード、ヘッダー、ボディを書き出すレスポンスの書き込み口です。
書き方はレスポンスを返すで扱います。
「r から読んで w に書く」の一往復は、競プロの標準入出力と同じ形です。
http.Handler インターフェース
「ハンドラ」の定義は、次のインターフェースです。
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}ServeHTTP メソッドを 1 つ持てば、どんな型でもハンドラとして扱われます。
インターフェースで見た「振る舞いだけを要求する」設計の実例です。
http.ListenAndServe の第 2 引数の型はこの http.Handler で、ServeMux 自身もハンドラの一種です。
サーバーは渡された 1 つの入口(mux)に丸投げし、入口が中で分配します。
この構造はミドルウェアの土台になります。
HandleFuncに渡した生の関数は、http.HandlerFuncというアダプタで内部的にハンドラ化されます。
404 はどこから来るか
curl -i(ステータス行とヘッダーまで表示)で、登録していないパスを叩きます。
curl -i http://localhost:8080/nothingHTTP/1.1 404 Not Found
Content-Type: text/plain; charset=utf-8
...
404 page not found合致するパターンがないとき、ServeMux が自分で 404 Not Found を返しています。
curl -i -X DELETE http://localhost:8080/hello も打ってみてください。
メソッドだけ違う場合は、405 Method Not Allowed が返ります。