I need to wrap the GetAssetsCompute
function inside a middleware
r.Handle("/api/v1/assets/ComputeBlade", GetAssetsCompute(assetService)).Methods("GET")
func GetAssetsCompute(assetService ServiceType) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// stuff here
})
}
but because middlewares take HTTP handlers as an argument and my function is not a handler, I can't.
I was thinking of doing something like this.
func GetAssetsCompute(assetService ServiceType) http.Handler {
return MyMiddleware(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// stuff here
}))
}
func MyMiddleware(next http.Handler) http.Handler {
}
Is this correct? Or is there a better way to do this. Also inside the middleware, I need to access the URL endpoint, do some processing and store this processed value and then again access that in the main handler. How can I do that?
EDIT: I want to apply this middleware to only a subset(>1) of endpoints I have. Not all
I also require the assetService
variable used in GetAssetsCompute(assetService ServiceType)
function in the handler. So, I need this closure too.
It seems you are trying to do 2 things. 1 - Apply a middleware to only some of your request handlers. 2 - Pass data from your middleware to your request handlers.
For the first one, I can think of three options. The first is what you are doing now, having a Middleware function in which you wrap your handler functions when you pass them to r.Handle
. Pseudocode:
r.Handle("/path1", Mware(Handler1())).Methods("GET")
r.Handle("/path2", Mware(Handler2())).Methods("GET")
r.Handle("/path3-nomiddleware", Handler3()).Methods("GET")
The second thing you could do is to add code to your middleware to filter based on URI path and then register your middleware using r.Use
. Pseudocode:
const mwarePaths []string = ...
func Mware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.RequestURI is in mwarePaths {
// do the middleware
}
}
}
r.Use(Mware)
Thirdly, you could put the code in a function which you call directly in your handlers and not register it like a middleware. Pseudocode:
func myUtil(w http.ResponseWriter, r *http.Request){ ... }
func GetAssetsCompute(assetService ServiceType) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
myUtil(w, r)
// stuff here
})
}
For the second thing - passing data from middleware to request handlers - here are some ideas.
First, if you go with the regular-function, no-middleware setup above, this problem disappears because anything you need in your handler can simply be a return value from your function.
If you do use a middleware, you can use the context
library (also from gorilla) to tie variables to an http.Request instance for passing to your handler: http://www.gorillatoolkit.org/pkg/context . Using that looks like this:
import "github.com/gorilla/context"
func middleware(...) {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
context.Set(r, "myKey", "bar")
}
}
func handler(w http.ResponseWriter, r *http.Request) {
val, ok := context.GetOk(r, "myKey") // returns "bar", true
}
Which of these options you choose to use is up to you (you know your needs). But, as mentioned in the comments, a good rule of thumb would be that code which handles unrelated concerns to what your request handlers do can be middleware. Code which handles concerns that are directly related to what your request handlers are doing can go directly in the handlers.