I have the following piece of code, and it doesn't work as expected. Specifically, all the requests to any endpoints are being handled as requests to either /banana/auth
or /banana/description
endpoints.
type Route struct {
AuthRoute string
DescriptionRoute string
}
var routes = [2]Route{
{
AuthRoute: "/apple/auth",
DescriptionRoute: "/apple/description",
},
{
AuthRoute: "/banana/auth",
DescriptionRoute: "/banana/description",
},
}
// ...
sm := http.NewServeMux()
for i, authServerConfig := range authServerConfigs {
authHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.Auth(w, r)
}
sm.Handle(routes[i].AuthRoute, authHandler)
descriptionHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.ServeDescription(w, r)
}
sm.Handle(routes[i].DescriptionRoute, descriptionHandler)
}
server := &http.Server{
// ...
Handler: sm,
// ...
}
server.ListenAndServe()
When I went ahead and replaced the for-loop with these statements, it worked exactly as I wanted:
authHandlerApple := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.Auth(w, r)
}
sm.Handle(routes[0].AuthRoute, authHandlerApple)
descriptionHandlerApple := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.ServeDescription(w, r)
}
sm.Handle(routes[0].DescriptionRoute, descriptionHandlerApple)
authHandlerBanana := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.Auth(w, r)
}
sm.Handle(routes[1].AuthRoute, authHandlerBanana)
descriptionHandlerBanana := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.ServeDescription(w, r)
}
sm.Handle(routes[1].DescriptionRoute, descriptionHandlerBanana)
The question is, what was I originally doing wrong and how can I avoid writing a clunky code as in the second example?
Per FAQ - What happens with closures running as goroutines, each closure shares that single variable authServerConfig
in the for
loop. To fix it, just add authServerConfig := authServerConfig
in the loop
for i, authServerConfig := range authServerConfigs {
authServerConfig := authServerConfig
authHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.Auth(w, r)
})
sm.Handle(routes[i].AuthRoute, authHandler)
descriptionHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.ServeDescription(w, r)
})
sm.Handle(routes[i].DescriptionRoute, descriptionHandler)
}