
Mux – A lightweight, fast HTTP request router for Go - loppers92
https://github.com/donutloop/mux
======
SEJeff
Does it use a trie? If not, it probably should. Here's a wonderful talk on
using that datastructure (with go) for the gov uk url router:

[https://gdstechnology.blog.gov.uk/2013/12/05/building-a-
new-...](https://gdstechnology.blog.gov.uk/2013/12/05/building-a-new-router-
for-gov-uk/)

The Vulcan proxy from Mailgun does the same thing:

[http://vulcand.github.io/proxy.html#route](http://vulcand.github.io/proxy.html#route)

It looks like it doesn't, so existing open source golang url routers will
perform much better, contrary to this post. The one in vuland is interesting
in that it supports both regex AND tries, so you get the best of both.

Additionally, httprouter (golang) uses a trie and is fast as hell:

[https://github.com/julienschmidt/httprouter](https://github.com/julienschmidt/httprouter)

Edit: Adding another one (thanks buro9!) that is used in production by
CloudFlare:

[https://github.com/pressly/chi](https://github.com/pressly/chi)

~~~
sorokod
Why is a trie obviously better then a hash map?

~~~
jeremiep
They allow you to match the URL in a series of steps. Where each step can be
static (ie "/foo") or dynamic (ie /images/).

You can then easily add features to this structure, like route middlewares at
every level in the tree; just apply them while doing the routing.

This also allows you to match route variants easily, ie "foo" and "foo/" are
the same, so are "/" and "/index.html". In the same way you can extract query
parameters for middleware/handler use.

~~~
mstade
Also, tries means it's trivial to do detect routing ambiguities, so your
routing table doesn't necessarily have to be built up front, or in any
particular order. This is particularly powerful when you're developing an
application with a team distributed both over space and time.

------
gkop
I don't usually say this but - isn't this a poor choice of name? Gorilla
framework's Mux [0] has been around awhile and is quite popular for routing in
Go.

[0] [https://github.com/gorilla/mux](https://github.com/gorilla/mux)

~~~
bradleyankrom
I typically read the HN comments before clicking on a link, and I actually
thought this _was_ a post about gorilla/mux until I got to your comment.

~~~
vegancap
Same here!

------
buro9
My favourite current HTTP request router is
[https://github.com/pressly/chi](https://github.com/pressly/chi)

The list of those using it in production includes:

\- Pressly

\- Cloudflare

\- Heroku

\- 99designs

\- Origami

\- IT Jobs Watch

\- CrowdRiff

At Cloudflare it's our default router for internal APIs, which are all written
in Go.

(and yes it uses a trie)

~~~
daenney
Do you know how it stacks up to httprouter for example? We can run benchmarks
all day but it would be cool if you happened to have some real production
statistics, by any change?

~~~
mmgutz
httprouter is unforgiving with routes. IIRC, having both of these routes are
not allowed

    
    
        /users/:id
        /users/create
    

Seems like a common use case.

~~~
peterkieltyka
Interesting.. and btw, pressly/chi supports those routes easily, among many
other combinations. Chi was designed to be very composeable with middlewares,
subrouters and handlers. The idea is to consider the request passing through a
"flow" of layers, handling and building the response along the way. This makes
it easier to reason and organize each piece separately and then connect it all
together.

------
nouney
From the README: "mux is a lightweight fast HTTP request router [...] It also
scales better."

Where can I find the benchmarks?

------
psiclops
Parts of the readme are copied from [0] julienschmidt/httprouter...

"In contrast to the default mux of Go's net/http package, this router supports
variables in the routing pattern and matches against the request method. It
also scales better."

[0]
[https://github.com/julienschmidt/httprouter](https://github.com/julienschmidt/httprouter)

------
1_2__3
If you're not going to explain in your readme or docs why anyone should use
this over the Gorilla library you're kind of wasting everyone's time.
Gorilla/Mux is very widely used and well-supported.

------
alexellisuk
+1 for the confusion with Gorilla's mux library. Have you benchmarked this
against Gorilla's lib to show why we would want to use this (relatively
unproven) library instead?

------
stcredzero
_It also scales better._

In what sense? Can it support many, many more routes? Or does it scale better
in the sense that it causes zero or near zero GC pressure? Better than what?

------
jstimpfle
What's the use case for all these routing libraries? Why not write a few lines
of procedural code? It's a natural encoding of the routes "trie".

    
    
         @methods('POST')
         def set_int(request):
             x = pop_int_component(request)
             no_more_components(request)
             do_set_the_int(x)
             return Ok
    
         def myapp(request):
             x = pop_id_component(request)
             if x == 'set_int':
                 return set_int(request)
             else:
                 return NotFound
    

No type system hacks, extremely modular and simple to understand. Exceptions
can replace basically all the boilerplate. The only drawback being there's no
URL generation, but it's not like most sites have so many URLs that writing
this by hand (directly in HTML templates or as "inverse functions") would be
unmaintainable.

~~~
peclink
All these routing libraries are just wrong level of abstraction. In HTTP you
have resources, and resources are not flat, they are hierarchical.

And hierarchy of resources defines some connection between then, and some
common properties (data, access level etc). So any resource can respond to
some HTTP method or can delegate to another, nested resource (if any) for any
method.

So (in PHP, from our still proprietary framework):

    
    
        // Index resource, just routing, no HTTP method handling.
        class IndexResource extends Resource {
          public function __construct(Application $app) {
            // ...
          }
          // Route nested resources for any request
          public function any(Request $request) {
            // Static path:
            $this->path(
               CollectionResource::Path, new CollectionResource($this)
            );
          }
        }
    
        class CollectionResource extends Resource {
    
            const Path = 'items';
    
            // Parent resource type constraint, you can access
            // parent data using IndexResource API:
            public function __construct(IndexResource $parent) {
              //...
            }
    
            // Route nested resources for any HTTP method:
            public function any(Request $request) {
               // Regexp pattern for URI segment:
               $this->match(ItemResource::Pattern, new ItemResource($this));
            }
    
            // Or handle GET
            public function GET(Request $request) {
              // ...
            }
            // Or POST maybe
            public function POST(Request $request) {
              // ...
            } 
        }
    
        class ItemResource extends Resource {
           const Pattern = '(\d+)';
    
           public function __construct(CollectionResource $parent) {
              // ...
           }
           public function any(Request $request, $prefix, $id) {
              $this->item = Item::find($id);
           }
    
           public function GET(Request $request) {
              return JSON::string($this->item);
           }
        }
    

It's not about routers + controllers etc, it's just resources + delegation to
nested resources:

\- recursive routes are trivial, so no problems with CMS-like applications; \-
looks good with type systems; \- no long routing tables (in fact, no routing
tables at all), so true modular apps; \- you can use anything (e.g. database)
for resources lookup, good for CMSes again; \- it's absolutely RESTful.

Yes, automatic URI building is not so easy, but it's kinda possible, in some
semi-automatic way.

I wonder why frameworks built this way are so uncommon (ours were inspired by
Bullet BTW).

~~~
twic
> In HTTP you have resources, and resources are not flat, they are
> hierarchical.

That isn't really true. There is nothing about HTTP, or even REST, that
requires resources to be hierarchical. That said, it is quite common, and
helpful for human beings, if they are hierarchical, so ...

> I wonder why frameworks built this way are so uncommon

Good question! The only one that springs to mind is Stapler:

[http://stapler.kohsuke.org/what-is.html](http://stapler.kohsuke.org/what-
is.html)

~~~
peclink
There is Bullet [http://bulletphp.com](http://bulletphp.com), that inspired
us, but it is too simple and lacks some important (for us) features, e.g.
recursion.

There are nested routes in Express and some Golang libraries (see gongular
near on HN), but they are not resource oriented. And yes, there are resources
in Rails, but it's sooo complex and heavy.

------
pbreit
Why does routing get so complicated? I use Web2py which doesn't even have a
router and it's _so_ much easier. Are regxes, variables, http methods all that
necessary in the router? Just pass the info to a controller.

~~~
hackerboos
If you don't need a router for web2py it's because WSGI is doing all the hard
work for you.

[https://en.wikipedia.org/wiki/Web_Server_Gateway_Interface](https://en.wikipedia.org/wiki/Web_Server_Gateway_Interface)

------
jratkevic
Top notch engineers behind this one!!

