5

I'm developing a new application and I'm trying to come up with a convention for defining routes. Ideally, I would like it to be simple, flexible, and reversible.

Here are some from popular frameworks:

Backbone

route                           matches
-----------------------------------------------------
help                            help
search/:query                   search/kiwis
search/:query/p:page            search/kiwis/p7
file/*path                      file/nested/folder/file.txt
docs/:section(/:subsection)     docs/faq, docs/faq/installing

Django

Uses regexes, but comes with a complex regex reverser

route                                                           matches
-------------------------------------------------------------------------------------
^articles/2003/$                                                /articles/2003/
^articles/(\d{4})/(\d{2})/$                                     /articles/2005/03/
^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$     /articles/2003/03/03/

Ruby on Rails

:controller/:action/:id/with_user/:user_id
books/*section/:title

ASP.NET / MVC 5

{controller}/{action}/{id}           /Products/show/beverages
{resource}.axd/{*pathInfo}           /WebResource.axd?d=...
{productId:int}/{productTitle}       /5/asp-net-mvc
books/{isbn?}                        /books, /books/1430210079

Django's is probably the most flexible, and it's already familiar to people that know regexes, but it's also the most difficult to read and reverse.

Backbone, RoR and ASP.NET all allow optional and wildcard/splat parts, with various syntaxes. MVC 5 has some options for restricting the parameters inline ala :int.

Where might these schemes fall short, and how could they be fixed?

Glorfindel
  • 3,137
  • 6
  • 25
  • 33
mpen
  • 1,889
  • 19
  • 29
  • 1
    [RFC 6570 URI Templating](http://tools.ietf.org/html/rfc6570) may be of some interest to you. – Mike Dec 13 '13 at 14:47
  • @Mike: Does that spec just cover *expansion* of URI templates, or does it cover *matching* as well? I need to go both ways. – mpen Dec 14 '13 at 00:57
  • Do you actually want comparison of the route formats only or about routing systems of those frameworks as whole? I don't know about backbone, but ruby on rails and asp.net mvc have a lot of routing features making them more flexible than django. – Mike Koder Dec 20 '13 at 08:49
  • @MikaKolari: Which features make them more flexible? I'm interesting in learning about the strengths and weaknesses and the tradeoffs that need to be made. For example, one route format may be super flexible but at the cost of being hideously complex. – mpen Dec 20 '13 at 21:43

2 Answers2

2

I've used ASP.NET MVC for years. Lately I've been doing research on Rails and Django to see if they have something more to offer. I've done reading the routing part of their documentation, but I haven't done any real apps yet, so I'm not an expert. I have no experience with Backbone, so I'll leave that out.

In short, Rails has the most powerful routing system of the three, Django has the weakest and ASP.NET MVC is somewhere between.

All have:
- named routes
- wildcards (in ASP.NET MVC only the last parameter)
- extra data (pass some values that are not part of the route)
- regex constraints
- helpers to create urls
- some kind of route prefix (namespace/area)

Ruby on Rails and ASP.NET MVC have:
- generic routing (one route, multiple controllers/actions)
- default values
- code constraints

Ruby on Rails has:
- resource routing
- powerful redirection

Example of regex constraint in Ruby on Rails (id has to be a number)

get ':controller/:id/:action', constraints: {id: /^\d+/}

Example of code constraint in ASP.NET MVC (check that {year}/{month}/{day} forms a valid date)

routes.MapRoute("date", "{year}/{month}/{day}", 
          new { controller = "Test", action = "Date" }, 
          new { year = @"\d{4}", month = @"\d{2}", day = @"\d{2}", date = new DateConstraint() }); 

// -----
public class DateConstraint : IRouteConstraint
{
    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        try
        {
            var year = int.Parse(values["year"] as string);
            var month = int.Parse(values["month"] as string);
            var day = int.Parse(values["day"] as string);
            var date = new DateTime(year, month, day);
            return true;
        }
        catch 
        {
            return false;
        }
    }
}

Example of redirection in Ruby on Rails

get '/stories/:name', to: redirect {|params, req| "/posts/#{params[:name].pluralize}" }
Mike Koder
  • 1,105
  • 1
  • 8
  • 6
  • Is that bit inside `#{}` eval'd Ruby or is it a limited syntax parsed by the router? What's "resource routing"? Does that mean you can create a route for an image and it will automatically set the headers/mimetype and such? – mpen Dec 21 '13 at 00:44
  • @Mark Yes, #{...} evals variables/expressions and puts the result in the string. Resource routing means that basic list, details, create, update, delete routes are defined with a single `resources :users` for example. See http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions for more – Mike Koder Dec 21 '13 at 12:30
0

How about manipulating you routes using Angular.js and js functions and conditionals? http://scotch.io/tutorials/javascript/single-page-apps-with-angularjs-routing-and-templating

  • A bit of example code would be helpful here. Link-only answers don't provide a lot of context, and the article you linked isn't obvious as to why that is better than any of teh optinos OP listed. – DougM Dec 19 '13 at 21:17
  • Can you elaborate on this a bit? You've basically just said "Angular" without any logic or reasoning behind it. – mpen Dec 19 '13 at 21:17