httpのhandlerに引数を指定する方法【Go】
htmlのtemplate【Go】 - 技術向上などで紹介した方法ですと、
各handlerで共通した、titleを取得する処理が行われています。
引数にtitleを渡すことで効率化できそうです。
... func viewHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[len("/view/"):] ... } func editHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[len("/edit/"):] ... } func saveHandler(w http.ResponseWriter, r *http.Request) { title := r.URL.Path[len("/save/"):] ... } func main() { http.HandleFunc("/view/", viewHandler) http.HandleFunc("/edit/", editHandler) http.HandleFunc("/save/", saveHandler) log.Fatalln(http.ListenAndServe(":8080", nil)) }
しかし、呼び出し元であるhttp.HandleFuncの第2引数には、
handler func(ResponseWriter, *Request)が指定されており、
呼び出し元でviewHandler(title)のようにhandler func(ResponseWriter, *Request)に対して新たな引数を指定することはできません。
そこで『「新たな引数を含む関数」を引数として、func(ResponseWriter, *Request)を返す関数』を作成し、
http.HandleFuncの第2引数に指定します。
ただし、「新たな引数」は呼び出し元では指定しません。titleはrequestのurlから取得できるからです。
... func viewHandler(w http.ResponseWriter, r *http.Request, title string) { // 第3引数titleを指定 p, err := load(title) if err != nil { http.Redirect(w, r, "/edit/"+title, http.StatusFound) return } renderTemplate(w, "view", p) } func editHandler(w http.ResponseWriter, r *http.Request, title string) { p, err := load(title) if err != nil { p = &Page{Title: title} } renderTemplate(w, "edit", p) } func saveHandler(w http.ResponseWriter, r *http.Request, title string) { body := r.FormValue("body") p := &Page{Title: title, Body: []byte(body)} err := p.save() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } http.Redirect(w, r, "/view/"+title, http.StatusFound) } var validPath = regexp.MustCompile("^/(view|edit|save)/([a-zA-Z0-9]+)$") // 正規表現をキャッシュ。「^」は先頭、「$」は末尾を意味する func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.HandlerFunc { // 3つの引数をもつfunctionを引数にとり、func(ResponseWriter, *Request)を返す return func(w http.ResponseWriter, r *http.Request) { m := validPath.FindStringSubmatch(r.URL.Path) // キャッシュした正規表現にマッチするpathを[]stringで格納 if m == nil { http.NotFound(w, r) // マッチしない場合は、404エラーを返す return } fn(w, r, m[2]) // 第3引数に[]string([全体、view|edit|save、title])の3番目titleを指定 } } func main() { http.HandleFunc("/view/", makeHandler(viewHandler)) // makeHandlerを呼び出す http.HandleFunc("/edit/", makeHandler(editHandler)) http.HandleFunc("/save/", makeHandler(saveHandler)) log.Fatalln(http.ListenAndServe(":8080", nil)) }
htmlファイルも含めた全体の構成はhttp.Redirect【Go】 - 技術向上を、
正規表現についてはregex(正規表現)【Go】 - 技術向上を参照ください。