Gorilla mux Handle any pattern with exception to static FileServer - go

I try to Handle any pattern another than "/app/*" to FileServer Handler. I use mux router to handle "/app/*" urls, and than I need to handle any others urls to static FileServer.This is my code:
r := mux.NewRouter()
r.Handle("/app/deleteComment", c.Handler(PreHandler(DeleteCommentHandler)))
r.Handle("/app/adminDeleteComment", c.Handler(PreHandler(AdminDeleteCommentHandler)))
(...)
fsa := justFilesFilesystem{http.Dir("build/")}
http.Handle("/", http.StripPrefix("/", http.FileServer(fsa)))
And now it works with pattern "/" but i want it to works with any pattern diffrent then "/app/*". I try it many ways but i think there is a simple solution how to handle it. Please help. Cheers.

Related

Gorilla mux - modify request before passing it to routers

Is there a way to catch a *http.Request object before It will be parsed and forwarded to Gorilla mux router handler?
For example, we have some routing map with their handlers:
r := mux.NewRouter()
r.HandleFunc("/products/{key}", ProductHandler)
r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
I plan to use a dynamic language prefix (2 symbols). Example:
without language code (for default language option):
https://example.com/products/1
https://example.com/articels/2
with language code:
https://example.com/ru/products/1
https://example.com/ru/articels/2
Is there a way to catch full URL in the middleware, extract language (if exists) and then after some modifications pass It to Gorilla mux routers? It will help to build beautiful URLs:
https://example.com/products/1 <- default language
https://example.com/ru/products/1 <- russian language (same resource but in different language)
That looks more attractive than this variant:
https://example.com/en/products/1 <- mandatory default language
https://example.com/ru/products/1 <- russian language
Something like this will probably work:
r := mux.NewRouter()
r.HandleFunc("/products/{key}", ProductHandler)
r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
m := http.NewServeMux()
m.HandeFunc("/", func(w http.ResponseWriter, req *http.Request) {
// do something with req
r.ServeHTTP(w, req)
})
http.ListenAndServe(":8080", m)

Golang sub-router alias

I have this right now:
// people
handler := routes.PersonHandler{}
subRouter := router.PathPrefix("/person").Subrouter()
subRouter.Use(authMiddleware)
handler.Mount(subRouter, routes.PersonInjection{People: models.PersonInit()})
I am wonder if there is a way to send both "/person" and "/people" to the same subrouter? Just in need of an alias at the moment.

Subroutes middlewares with Gorilla MUX and Negroni

I'm trying to add a middleware only on some routes. I wrote this code:
func main() {
router := mux.NewRouter().StrictSlash(false)
admin_subrouter := router.PathPrefix("/admin").Subrouter()
//handlers.CombinedLoggingHandler comes from gorilla/handlers
router.PathPrefix("/admin").Handler(negroni.New(
negroni.Wrap(handlers.CombinedLoggingHandler(os.Stdout, admin_subrouter)),
))
admin_subrouter.HandleFunc("/articles/new", articles_new).Methods("GET")
admin_subrouter.HandleFunc("/articles", articles_index).Methods("GET")
admin_subrouter.HandleFunc("/articles", articles_create).Methods("POST")
n := negroni.New()
n.UseHandler(router)
http.ListenAndServe(":3000", n)
}
I expect to see request logs only for paths with prefix /admin. I do see a log line when I do "GET /admin", but not when I do "GET /admin/articles/new". I tried by brute force other combinations but I can't get it. What's wrong with my code?
I saw other ways, like wrapping the HandlerFunc on each route definition, but I wanted to do it once for a prefix or a subrouter.
The logging middleware I'm using there is for testing, maybe an Auth middleware makes more sense, but I just wanted to make it work.
Thanks!
Issue is the way you create an sub routes /admin. Complete reference code is here https://play.golang.org/p/zb_79oHJed
// Admin
adminBase := mux.NewRouter()
router.PathPrefix("/admin").Handler(negroni.New(
// This logger only applicable to /admin routes
negroni.HandlerFunc(justTestLogger),
// add your handlers here which is only appilcable to `/admin` routes
negroni.Wrap(adminBase),
))
adminRoutes := adminBase.PathPrefix("/admin").Subrouter()
adminRoutes.HandleFunc("/articles/new", articleNewHandler).Methods("GET")
Now, access these URLs. You will see logs only for /admin sub routes.

Set gorilla mux subrouter

If I have a mux.Router, how do I set it to be a "subrouter"? All examples I can find creates a new router by calling Route.Subrouter() and then setting Handlers on it, but I already have a router!
// does not know about "/api/v1/"
v1_router := mux.NewRouter()
subrouter.HandleFuc("/route1/", ...)
subrouter.HandleFuc("/route2/", ...)
// does not now about route1, route2
r := mux.NewRouter()
r.PathPrefix("/api/v1/").???(v1_router)
I hope I'm making sense...
I feel the same way, and have to live with the same "workaround". I would like to set the subrouter to an existing router. Like:
r.PathPrefix("/api").SetSubrouter(api.GetRouter()) //won't work
That would let my api feel more autonomous / loosely coupled. But getting a subrouter is all we have from gorilla.
s := r.PathPrefix("/api").Subrouter()
api.SetRoutes(s)
You can do it like this:
v1 package file:
func Handlers(subrouter *mux.Router) {
//base handler, i.e. /v1
r.StrictSlash(true)
subrouter.HandleFuc("/route1/", ...)
subrouter.HandleFuc("/route2/", ...)
}
main file:
r := mux.NewRouter()
package.Handlers(r.PathPrefix("/api/v1").Subrouter())

Nesting subrouters in Gorilla Mux

I've been using gorilla/mux for my routing needs. But I noticed one problem, when I nest multiple Subrouters it doesn't work.
Here is the example:
func main() {
r := mux.NewRouter().StrictSlash(true)
api := r.Path("/api").Subrouter()
u := api.Path("/user").Subrouter()
u.Methods("GET").HandleFunc(UserHandler)
http.ListenAndServe(":8080", r)
}
I wanted to use this approach so I can delegate populating the router to some other package, for example user.Populate(api)
However this doesn't seem to work. It works only if I use single Subrouter in the chain.
Any ideas?
I figured it out, so I'll just post it here in case someone is as stupid as I was. :D
When creating path-based subrouter, you have to obtain it with PathPrefix instead of Path.
r.PathPrefix("/api").Subrouter()
Use r.Path("/api") only when attaching handlers to that endpoint.
For those who are struggling to split between auth and noauth routes, the following works fine for me:
r := mux.NewRouter()
noAuthRouter := r.MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) bool {
return r.Header.Get("Authorization") == ""
}).Subrouter()
authRouter := r.MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) bool {
return true
}).Subrouter()
Then you can apply middleware for authRouter only
If you need to Separate out the UI and API routers, you can simply do what the OP suggested:
appRouter := r.PathPrefix("/").Subrouter()
appRouter.Use(myAppRouter)
apiRouter := r.PathPrefix("/api").Subrouter()
apiRouter.Use(myAPIRouter)
Many thanks for the OP for providing the answer. Hopefully having it all in one place for my use case will help someone.

Resources