【非推奨】Go の net/http でパスパラメータ取得

【2022/02/20追記】この記事のまま実装すると /v1/blogs/blogs/1 みたいな不正なパスでも通ってしまうことが判明したため参考にしないでください。

今 Go で作成している API はフレームワークを使用せず net/http で作っているのだが、パスパラメータをうまいこと扱うような機能は存在しないらしい。

REST API 想定で /v1/blogs/:id みたいなルーティングをしたい場合

http.HandleFunc("/v1/blogs/", middleware.AuthMiddleware(dib.CRUD))

のように、/v1/blogs/ というルーティングを登録する。

ハンドラ側ではアクセスされた URL を filepath.Split を使って分割。今回は整数が渡ってくることを想定しているので整数にキャストし、キャストできなければエラーとする。

func (h *BlogHandler) CRUD(w http.ResponseWriter, r *http.Request) {
	sub := strings.TrimPrefix(r.URL.Path, "/blogs")
	_, idstr := filepath.Split(sub)
	if idstr == "" {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	id, err := strconv.Atoi(idstr)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		return
	}

	if r.Method == http.MethodGet {
		// 取得
		fmt.Fprintf(w, strconv.Itoa(id))
		return
	}
	if r.Method == http.MethodPost {
		// 新規登録
		w.WriteHeader(http.StatusNotImplemented)
		return
	}
	if r.Method == http.MethodPut {
		// 編集
		w.WriteHeader(http.StatusNotImplemented)
		return
	}
	if r.Method == http.MethodDelete {
		// 削除
		w.WriteHeader(http.StatusNotImplemented)
		return
	}
	w.WriteHeader(http.StatusMethodNotAllowed)
}

また GET/POST/PUT/DELETE ごとにルーティングを設定するという機能も無いので、ハンドラの中で自分で振り分ける。

このあたりはフレームワークを使ったほうが簡単ではあるが、フレームワークの学習コストもあるし、フレームワークが廃れたときに共倒れしたくないので net/http を使っている。