-
Notifications
You must be signed in to change notification settings - Fork 227
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Clean sub-router mounts #97
Conversation
Subroutes used to look a lot more like this, actually. I ended up changing the functionality to what you see today because I think of Also, [1]: a bunch of other frameworks make this same distinction. I know I tested Sinatra, and I think I also tested Flask. While I hate to use this as justification for Goji's behavior here, at least it means I'm not completely off my rocker :) |
Well, I'm not married to the syntax or implementation, but I'm just speaking of what would be the expected functionality when you create a namespace that represents a sub-resource. For example, think of a filesystem -- you can access a directory by Also, think about when you set Btw hrmm.. perhaps a better solution to this PR then is to have.. base := web.New()
base.Get("/", index)
base.Get("/hello", hello)
admin := web.New()
admin.Get("/", adminIndex)
admin.Post("/", adminCreate)
admin.Get("/:adminId", adminGet)
base.Handle("/admin", Mount(admin))
// or...
base.Mount("/admin", admin) I don't think |
Neither of those would work, because routing is a function of the pattern, not the handler or the mux. But back to the philosophical question at hand, I don't think The root of a domain is actually a special case: something like
|
I think this is getting a bit extreme to nit-pick such a detail that could really go 50/50, so why not support both cases? Question, if you were designing + writing a REST API with Goji, and you had a resource, I think its fair that you say they are different, and stricter design would lean on the side to do a 301 from |
I agree with Carl: What's wrong with expecting your clients to use the proper URL?? |
You're right: I'd probably design the routes as Perhaps the misunderstanding here is about the vision for how much abstraction power Goji provides (or ought to provide). It's always been my intention to give users all the primitives they require to build websites and APIs, but to provide very few of the higher-level abstractions. I fully expect users to write higher-level utilities on top of Goji (e.g., you could make an "API resource" helper function that correctly dealt with the sub-router and redirects), but I'm not confident enough in any one design to include them in the base project. In this sense, "micro-framework" is perhaps a bit of a misnomer: Goji is in some strong sense a routing and middleware library. Does that make sense? And please let me know if I'm misunderstanding or misrepresenting you :) |
Yea I also agree that I am saying that I should be able to through a single statement to a router, mount a sub application to that router something like this: base.Get("/", someroute)
// Create and mount admin sub-router
adminRouter := web.New()
adminRouter.Use(middleware.SubRouter)
adminRouter.Get("/", adminIndexHandler)
adminRouter.Post("/", createAdminHandler)
base.Handle("/admin*", adminRouter)
// Create and mount sites sub-router
sitesRouter := web.New()
sitesRouter.Use(middleware.SubRouter)
sitesRouter.Get("/", sitesIndexHandler)
sitesRouter.Post("/", createSitesHandler)
base.Handle("/sites*",sitesRouter) ... NOT as currently is .........: base.Get("/", someroute)
// Create and mount admin sub-router
adminRouter := web.New() // likely defined in the admin package itself
adminRouter.Use(middleware.SubRouter)
adminRouter.Get("/", adminIndexHandler)
adminRouter.Post("/", createAdminHandler)
base.Handle("/admin/*", adminRouter)
base.Get("/admin", adminIndexHandler) // ...pls no..
base.Post("/admin", createAdminHandler) // ...pls no..
base.Get("/admin/", http.RedirectHandler("/admin", 301)) // ...pls no..
base.Post("/admin/", http.NotFoundHandler()) // ...pls no..
// Mount sites sub-router
sitesRouter := web.New() // likely defined in the sites package itself
sitesRouter.Use(middleware.SubRouter)
sitesRouter.Get("/", sitesIndexHandler)
sitesRouter.Post("/", createSitesHandler)
base.Handle("/sites*", sitesRouter)
base.Get("/sites", sitesIndexHandler) // ...pls no..
base.Post("/sites", createSitesHandler) // ...pls no..
base.Get("/sites/", http.RedirectHandler("/sites", 301)) // ...pls no..
base.Post("/sites/", http.NotFoundHandler()) // ...pls no.. .. do you see...? The web app that I wrote with Goji has 10 sub-routers... you can imagine why I am so frustrated about this code cruft. If you see a better way and can fix my example above, then I am happy to admit being wrong and apologize for wasting your time, but I'm not seeing it. ... I hear you that this PR and example in this comment still uses Another proposal, as I mentioned, is to support Perhaps other ideas could be proposed to this issue that I've put forth, or let me know it will never be fixed and I will accept that and move on to another http router. |
Would a helper function be appropriate for your use case? // Everything is completely untested
func fakeRoot(h web.Handler) web.Handler {
fn := func(c web.C, w http.ResponseWriter, r *http.Request) {
c.URLParams["*"] = "/"
h.ServeHTTPC(c, w, r)
}
return web.HandlerFunc(fn)
}
func SubRoute(prefix string, h web.Handler) {
goji.Get(prefix, fakeRoot(h))
goji.Handle(prefix, fakeRoot(h))
goji.Get(prefix + "/", func(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, prefix, 301)
})
goji.Handle(prefix + "/", http.NotFound)
goji.Handle(prefix + "/*", h)
} Now you can do something like this: SubRoute("/admin", adminRouter)
SubRoute("/sites", siteRouter) |
thanks Carl! I'll give that a shot |
@zenazn thanks for that, I have a variation of that solving my problem now. I still think it would be nice to have a |
This change adds support for wildcard patterns that connect the slashes of a sub-router.
For example.. the current behaviour:
getting a list of users, or creating a new user, the client would have to specifically request:
GET /users/
POST /users/
A GET to /users or POST to /users will result in a 404.... which is certainly not the conventional or expected behaviour of an API.
in order to support both
/users/
and/users
, you have to individually add those routes as so:.. and as a I add more and more groups of handlers (sub-routers), its polluting my code.
This PR, allows both cases to work, depending if the wildcard route provided is
/*
or*
. As so:Also, this change is fully backwards compatible with the previous functionality. For a full example, see: https://gist.github.com/pkieltyka/3afcfd34bd45f29fe372