🔩 ねじき教室 Go と Web の教室

ルーティングとハンドラ

読了目安 約3分

http.ServeMux で複数のパスを捌き、ハンドラの 2 つの引数と http.Handler インターフェースの正体を読み解きます。

この章の目次

リクエストのパスとメソッドを見て、処理するハンドラを振り分けることをルーティングと呼びます。

ServeMux にルートを登録する

次の内容を main.go に保存してください。 Go 1.22 以降が前提です。

Go
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/users

curl -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 つの引数

どのハンドラも同じ形です。

Go
func(w http.ResponseWriter, r *http.Request)

r *http.Request は、受信したリクエストの情報が詰まった struct へのポインタです。 Part 2 で見た HTTP の要素が、そのままフィールドです(r.Methodr.URL.Pathr.Headerr.Body)。

w http.ResponseWriter は、ステータスコード、ヘッダー、ボディを書き出すレスポンスの書き込み口です。 書き方はレスポンスを返すで扱います。

r から読んで w に書く」の一往復は、競プロの標準入出力と同じ形です。

http.Handler インターフェース

「ハンドラ」の定義は、次のインターフェースです。

Go
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/nothing
テキスト
HTTP/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 が返ります。