As we known, standard httprouter func has 3 parameters like below:
func ViewIndex(w http.ResponseWriter, r *http.Request, ps httprouter.Params){}
Sometimes, we need pass additional arguments to httprouter handle func, like:
func ViewIndex(w http.ResponseWriter, r *http.Request, ps httprouter.Params, settings map[string]string){}
There are two ways to achive this target:
- Use a wrapper
func getIndexWithSettings2(s Settings) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { // Settings is in the scope and ps httprouter.params fmt.Println(s.Path) } }
-
Use a middleware
func settingsMiddleware(h http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Take the context out from the request ctx := r.Context() // Get the settings s := somewhere() // Get new context with key-value "settings" ctx = context.WithValue(ctx, "params", s) // Get new http.Request with the new context r = r.WithContext(ctx) // Call your original http.Handler h.ServeHTTP(w, r) }) }
Full example
package main
import (
"context"
"fmt"
"net/http"
"github.com/julienschmidt/httprouter"
)
func main() {
r := httprouter.New()
index := settingsMiddleware(http.HandlerFunc(getIndex))
r.GET("/index", wrapHandler(index))
http.ListenAndServe(":8080", r)
}
func wrapHandler(h http.Handler) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
// Take the context out from the request
ctx := r.Context()
ctx = context.WithValue(ctx, "params", ps)
r = r.WithContext(ctx)
h.ServeHTTP(w, r)
}
}
func settingsMiddleware(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var s = "/var/bin"
ctx := r.Context()
ctx = context.WithValue(ctx, "settings", s)
r = r.WithContext(ctx)
h.ServeHTTP(w, r)
})
}
func getIndex(w http.ResponseWriter, r *http.Request) {
s, ok := r.Context().Value("settings").(string)
if !ok {
fmt.Println("s is not type string")
}
fmt.Println(s) // "/var/bin"
}