I'm fairly new to Go and trying to create a middleware implementation in a gateway library that I'm building on top of mux
. So far, I've come up up with this:
type (
MyContext struct {
// ...
}
APIGateway struct {
mux *mux.Router
ctx *MyContext
}
)
type MiddlewareFunc func(*MyContext) func(http.Handler) http.Handler
func (a APIGateway) Use(mw MiddlewareFunc) {
a.mux.Use(mw(ctx))
}
This works, but then I have to deal with a lot of boilerplate code. The simplest middleware implemented on this pattern has to have a minimum of two return statements and lot of incline function declaration.
func someMiddleware(ctx *MyContext) func(http.Handler) http.Handler {
return func(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Application Logic here
handler.ServeHTTP(w, r)
})
}
}
This quickly becomes a bigger problem when the middlware has to take some extra parameters since now it has to deal with three return statements:
func LogginMiddleware(c LoggerConfig) MiddlewareFunc {
return func(ctx *MyContext) func(http.Handler) http.Handler {
return func(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// ...
handler.ServeHTTP(w, r)
// ...
})
}
}
}
Is there a way I can possibly reduce the involvement of boilerplate code?
You have this problem because the middleware functions are implemented as closures. Note that middleware function is defined as:
type MiddlewareFunc func(http.Handler) http.Handler
where http.Handler
is an interface. So you can write something like this for each middleware:
type MyMiddleware struct {
// Fields your middleware func needs
Next http.Handler
}
// This is the middleware func
func MW(next http.Handler) http.Handler {
m:=MyMiddleware{Next:next}
// Initialize other fields
return m
}
// Implement http.Handler.
func (m MyMiddleware) ServeHTTP(wr http.ResponseWriter, req *http.Request) {
// Do middleware stuff
m.Next.ServeHTTP(w,req)
}