Better handling of http router pattern

5,501 views
Skip to first unread message

bsr

unread,
Feb 28, 2011, 6:45:42 PM2/28/11
to golang-nuts
Hello,
I am struggling a bit to register the http route to handle below
patterns. I am trying RESTful URL patterns as explained here (http://
microformats.org/wiki/rest/urls)

GET /people
--> this is possible with http.HandleFunc("/people", peopleHandler)

GET /people/new
--> this is possible with http.HandleFunc("/people/new",
peopleNewHandler)

POST /people
--> this can be done by filtering on request.Method of peopleHandler
switch r.Method {
case "GET":
//handle
case "POST":

I am having trouble with the below formats

GET /people/1

GET /people/1/edit

I could think about doing it through string manipulation in
peopleHandler to see whether these patterns matches..This gets messy
as the url becomes

GET /people/1/phones/23

etc.. Also, the same logic needs to repeat for other controllers like

GET /po
GET /po/1

etc..

I see two good web packages, twister and web.go. I think they allow
to use regex patterns rather than string for router handler
registration. I prefer not to use those packages as they implement
their own http packages, and prefer to stick with core. Any future
plans to improve easing the registration and retrieving url
parameters?

An example from twister (simple go wiki example)

Register("/<artnum:.*>", "GET", show, "POST", update)

id, _ := strconv.Atoi(req.Param.Get("artnum"))


Thanks.



Evan Shaw

unread,
Feb 28, 2011, 7:53:36 PM2/28/11
to bsr, golang-nuts
On Tue, Mar 1, 2011 at 12:45 PM, bsr <bsr...@gmail.com> wrote:
> I see two good web packages, twister and web.go. I think they allow
> to use regex patterns rather than string for router handler
> registration. I prefer not to use those packages as they implement
> their own http packages, and prefer to stick with core. Any future
> plans to improve easing the registration and retrieving url
> parameters?
>
> An example from twister (simple go wiki example)
>
> Register("/<artnum:.*>", "GET", show, "POST", update)
>
> id, _ := strconv.Atoi(req.Param.Get("artnum"))

You can create a handler for this outside of the http package, which
is (IMO) where it belongs. I'm not even convinced that it belongs in
the core library, as there are many ways you can do URL routing and
none of them are standard. It's the kind of thing that there would be
lots of disagreement and bikeshedding about.

Here's a simple way to route with regexps that passes the parameters
as a slice of strings:

(warning: uncompiled/untested code lies ahead)

type route struct {
re *regexp.Regexp
handler func(http.ResponseWriter, *http.Request, []string)
}

type RegexpHandler struct {
routes []*route
}

func (h *RegexpHandler) AddRoute(re string, handler
func(http.ResponseWriter, *http.Request, []string)) {
r := &route{regexp.MustCompile(re), handler}
h.routes = append(h.routes, r)
}

func (h *RegexpHandler) ServeHTTP(rw http.ResponseWriter, r *Request) {
for _, route := range h.routes {
matches := route.re.FindStringSubmatch(r.RawURL)
if matches != nil {
route.handler(rw, r, matches)
break
}
}
}

For your case, you can do something like:

reHandler := new(RegexpHandler)
reHandler.AddRoute("/people/[0-9]+/edit$", peopleEditHandler)
http.ListenAndServe(":8080", reHandler)

- Evan

bsr

unread,
Feb 28, 2011, 8:32:08 PM2/28/11
to golang-nuts
Evan.. thank you very much for the detailed reply... I too like things
to be minimal, and your approach works for me.. this group is so
responsive, and thanks all...
Message has been deleted

Russ Cox

unread,
Feb 28, 2011, 10:37:03 PM2/28/11
to bsr, golang-nuts
The standard library is not going to use a regexp-based
handler dispatch by default, because doing so makes it much
more difficult to resolve conflicts. The current path-based
mux will let you register for "/" to catch everything and
then "/foo" to catch just "/foo", and the latter takes precedence
over the former because it is a more specific match.
Defining "more specific" becomes significantly murkier
when the patterns are regular expressions instead of just
prefixes. It can be done, but it's expensive and the result
would probably not be easy to explain or predict in the
general case. The path-based mux scales better.

Of course, as Evan said, there's nothing stopping you from
writing your own regexp-based mux and registering it to
handle "/". That's part of the beauty of interfaces.

Russ

Message has been deleted

roger peppe

unread,
Mar 1, 2011, 4:11:35 AM3/1/11
to golan...@googlegroups.com, gary b, bsr
On 1 March 2011 06:02, gary b <gary...@gmail.com> wrote:
> Many regexp routers avoid the "more specific" problem by matching patterns
> in the order that the patterns are specified.

if you continue to allow the current Go approach
of allowing separate packages to register their
own http handlers (for example expvar), then this
can't work, as init functions are called in arbitrary
order.

Russ Cox

unread,
Mar 1, 2011, 7:52:17 AM3/1/11
to golan...@googlegroups.com, gary b, bsr
On Tue, Mar 1, 2011 at 01:02, gary b <gary...@gmail.com> wrote:
> Many regexp routers avoid the "more specific" problem by matching patterns
> in the order that the patterns are specified. Routing is easy to understand
> because most or all of the routing for an application is
> specified declaratively by a list of regular expressons. Contrast this with
> ServeMux applications where routing logic is spread out through one or more
> handlers

indeed, and this is something we want to keep.

Message has been deleted

Russ Cox

unread,
Mar 1, 2011, 4:24:00 PM3/1/11
to golan...@googlegroups.com, gary b, bsr
On Tue, Mar 1, 2011 at 15:10, gary b <gary...@gmail.com> wrote:
>> if you continue to allow the current Go approach
>> of allowing separate packages to register their
>> own http handlers (for example expvar),
>
> The handler registration in the expvar package illustrates some of the
> problems with decentralized registration:

if you don't want to use the default handlers,
don't use the default servemux.

russ

niloy....@gmail.com

unread,
Mar 16, 2015, 9:51:29 AM3/16/15
to golan...@googlegroups.com, bsr...@gmail.com, chick...@gmail.com
This is very old thread but still I would like to point out that Evan's solution will not work sometime and you can't predict when

say if you have pattern like

/people/[0-9]+/edit$  ---> handler1
/people/[0-9]+/[a-zA-Z]$  ---> handler2

and if your url is,
"/people/21/edit" then it is not guaranteed that the pattern always be evaluated to handler1
Reply all
Reply to author
Forward
0 new messages