How to use middlewares when using julienschmidt/httprouter in goLang?
go, middleware
Solution
This issue is not with your middleware handler. You are getting errs because `User.CreateUser` is not of type `http.Handler`.
Try this pattern :
The important bit is to return a `http.Handler` and wrap `func(w http.ResponseWriter, r *http.Request)` with `http.HandlerFunc`.
func Handler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// do stuff
})
}
go source :
// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
Based on your feedback:
`httprouter.Handle` does not implement `ServeHTTP`. It is called directly. For example : `next(w, r, ps)`
Below you will find examples of middleware handlers.
// Middleware without "github.com/julienschmidt/httprouter"
func StdToStdMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// do stuff
next.ServeHTTP(w, r)
})
}
// Middleware for a standard handler returning a "github.com/julienschmidt/httprouter" Handle
func StdToJulienMiddleware(next http.Handler) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
// do stuff
next.ServeHTTP(w, r)
}
}
// Pure "github.com/julienschmidt/httprouter" middleware
func JulienToJulienMiddleware(next httprouter.Handle) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
// do stuff
next(w, r, ps)
}
}
func JulienHandler() httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
// do stuff
}
}
func StdHandler() http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// do stuff
})
}
func main() {
router := httprouter.New()
router.POST("/api/user/create", StdToJulienMiddleware(StdHandler()))
router.GET("/api/user/create", JulienToJulienMiddleware(JulienHandler()))
log.Fatal(http.ListenAndServe(":8000", router))
}
Problem
What's the best way to chain middlewares while using julienschmidt/httprouter? As far as I have googled, http.HandlerFunc accepts functions only in the form `func (w ResponseWriter, r *Request)` whereas httprouter.Handle functions are of the form `func (w http.ResponseWriter, r *http.Request, ps httprouter.Params)`. How to I chain middlewares without converting the httprouter.Handle function into http.HandlerFunc? For example: My routes.go is of the form, ``` router := httprouter.New() router.POST("/api/user/create", middlewares.EscapeStringsMiddleware(User.CreateUser)) log.Fatal(http.ListenAndServe(":8000", router)) ``` How do I write middleware functions for the above mentioned route? Already tried methods: 1. ``` func EscapeStringsMiddleware(next http.Handler) httprouter.Handle { return func (response http.ResponseWriter, request *http.Request, ps httprouter.Params) { err := request.ParseForm() if err != nil { panic(err) } for key, values := range request.Form { for i, value := range values { value = template.HTMLEscapeString(value) value = template.JSEscapeString(value) request.Form[key][i] = value } } next.ServeHTTP(response, request) } } ``` Error obtained: ``` cannot use User.CreateUser (type func(http.ResponseWriter, *http.Request, httprouter.Params)) as type http.Handler in argument to middlewares.EscapeStringsMiddleware: func(http.ResponseWriter, *http.Request, httprouter.Params) does not implement http.Handler (missing ServeHTTP method) ``` 2. ``` func EscapeStringsMiddleware(next httprouter.Handle) httprouter.Handle { return func (response http.ResponseWriter, request *http.Request, ps httprouter.Params) { err := request.ParseForm() if err != nil { panic(err) } for key, values := range request.Form { for i, value := range values { value = template.HTMLEscapeString(value) value = template.JSEscapeString(value) request.Form[key][i] = value } } next.ServeHTTP(response, request) } } ``` Error obtained: ``` next.ServeHTTP undefined (type httprouter.Handle has no field or method ServeHTTP) ``` Also how do I chain multiple middleware? For example, ``` router.POST("/api/user/create", middlewares.VerifyCSRF(middlewares.EscapeStringsMiddleware(User.CreateUser))) ```