-
Notifications
You must be signed in to change notification settings - Fork 11
Discussion: Top-Level Router API #1
Comments
It's ok to have both A Subrouter is a very lightweight route factory, while Router carries data and logic that go well beyond this. Making Subrouter() return *Router would mix this distinction and require Router to have a prefix and a router field itself (empty and nil for the main Router) and check if it is the main router in every method, and call the main router if not, and so on, while a Subrouter would not use any of the fields used by the main router. It would be a type trying to act as two types, and this sounds like a messy design. So Subrouter should only have methods to create a Route and another Subrouter. I don't see it having more than 2 methods, ever. Maybe Subrouter just needs a better name, because it's not really a router. |
The http.HandlerFunc type should not be used as the handler function argument type. The documentation for http.HandlerFunc does not apply to the use of the type in this package. The HandlerFunc.ServeHTTP method is not needed here. Both of these issues can confuse newbies. I suggest using the anonymous function type |
Interesting. I never even considered not using HandlerFunc, but thinking about it, the anonymous function way would suffice. |
RE: the sub-router having only two methods - this might confuse users since you don't get access to any of the convenience methods on e.g. s := r.Sub("/users")
s.Handle("/new", myHandler) // matches "/users/new"
s2 := s.Sub("/{id}")
s2.Handle("/", myHandler) // matches "/users/{id}/"
s2.Handle("/tickets", myHandler) // matches "/users/{id}/tickets" ... could instead be: r := router.New()
r.Get("/", indexHandler)
s := router.New()
r.Handle("/users", s) // tell the top-level router to pass any requests prefixed with "/users" to s.
s.Handle("/new", userHandler) // matches "/users/new"
s.Get("/list", userList) // matches "/users/list" This is functionally similar to the way Goji (https://godoc.org/github.com/zenazn/goji/web#Mux) tackles sub-routers. You can have packages initialize their own routers (e.g. JSON API, web, static) and then import them in your |
In this case: r := router.New()
r.Get("/", indexHandler)
s := router.New()
r.Handle("/users", s)
s.Handle("/new", userHandler)
s.Get("/list", userList) ...when you call |
This may be just my opinion, but I think we could do without the convenience functions. It makes declarations less readable because there's more different kinds of functions, and |
Another thing to consider is to use option types like the CSRF package instead of strings, and then have the function be |
@elithrar: The name Subrouter in this initial proposal is a bit misleading, because it is not doing any nested dispatch, nor it's merging routes from one router into another. It is just a convenience to register URL's that share a common prefix (a domain and/or path). It's dumb but kinda lovely. To achieve what you want, we would need something different. For example, package1 defines a router: r := mux.New()
r.Route("/bar").Handler(barHandler) And package2 imports it and submounts it under a given prefix: r := mux.New()
r.Mount("/foo", package1.r) In the end, only package2's router would know how to build the URLs that are being served, though. |
Here's an example without the convenience functions:
and the same example with the convenience functions:
|
The convenience functions are a delicate dilemma. Sure, the API would be tidier without them, and they could be defined elsewhere through proxy types, but they make usage easier and prettier for common enough scenarios, and I think it has been proved that people like them. |
I'm definitely +1 for the convenience functions. They make sense when you On Tue, Oct 27, 2015 at 7:40 AM rodrigo moraes notifications@github.com
|
@moraes I definitely think |
@AaronO, soon: // Mount imports all routes from the given router into this one.
//
// Combined with Sub() and Name(), it is possible to submount routes using
// pattern and name prefixes:
//
// r := New()
// s := r.Sub("/admin").Name("admin:").Mount(admin.Router) |
I have a use case where I want to combine routers. Some method to let me do that would simplify my code by 200+ lines. With a way to combine routers, I could drop half of my documented features: http://godoc.org/github.com/BlueOwlOpenSource/endpoint |
Might as well start this to pick up where gorilla/mux#130 leaves off.
Some high-level comments:
func (r *Route) Handler(handler http.HandlerFunc, methods ...string) *Route
should accept ahttp.Handler
and have a sister methodHandleFunc
that accepts ahttp.HandleFunc
.Get
,Head
, etc. convenience methods—additional methods for these would clutter the API.router.Sub
return a*Router
instead, allowing you to use the same methods as you would on a*Router
?prefix
could be a field of Router that the call torouter.Sub
sets.The text was updated successfully, but these errors were encountered: