URI mapping in exyus

2007-12-05 @ 17:36#

scottgu posted another tutorial on the new ASP.NET MVC Fx this week. interesting stuff. this latest article covers how the MVC Fx handles URL-to-code routing and also how to customize it to meet your needs. it all looks pretty rails-like to my eyes. as i am using scott's pieces as impetus for checking my exus engine for features and functionality, i thought i'd post a piece on how URI routing works in exyus.

URI routing in exyus is very straightforward. you simply add one or more URI patterns to the resource class itself - as a custom attribute. for example, here's a simple static resource class that returns a string of data:

[UriPattern(@"/qotd/(\.xcs)(.*)?")]
public class getQuote : GetHandler
{
  public getQuote()
  {
    this.ContentType = "text/plain";
    this.Content = "\"You cannot get ahead while you are getting even.\" -- Dick Armey";
  }
}

the [UriPattern(@"/qotd/(\.xcs)(.*)?")] line is the routing rule for this resource. in this case, the regular expression indicates that any call to "/qotd/.xcs" will be routed to this resource class.

NOTE: all URLs in the exyus engine contain the ".xcs" tail. this is added as part of a rewrite rule 'under the covers' and is not normally included in the actual browser URL.

you can associate a resource class with more than one UriPattern. for example, if you wanted the same getQuote resource to appear for several URLs, you could use the following UriPattern:

[UriPattern(@"/qotd/(\.xcs)(.*)?",@"/dick-armey-quote/(\.xcs)(.*)?",@"/on-getting-even/(\.xcs)(.*)?")]

of course, the UriPattern can be more interesting. for example, you can write a rule that covers GET(list), GET(item), as well as PUT, POST, and DELETE. since the resource classes in exyus are already built to handle the major HTTP methods, it's just a matter of crafting the proper regular expression to handle the URL queries. here's one that is built to handle read/write actions on a "User" resource:

// example xmlfile handler
[UriPattern(@"/users/(?<uid>[^/]*)(?<tail>\.xcs)")]
public class userFile : FileHandler
{
    public userFile()
    {
        this.AllowPost = false;
        this.AllowCreateOnPut = true;
        this.DocumentsFolder = "~/documents/users/";
        this.StorageFolder = "~/storage/users/";
        this.XHtmlNodes = new string[] { "//notes" };
        this.LocalMaxAge = 600;
        this.ImmediateCacheUriTemplates = new string[]
            {
                "/users/",
                "/users/{uid}"
            };
    }
}

notice the use of the argument name pattern (<uid>) in the UriPattern attribute. this will make sure that, if the user id is supplied, it will be available as a token when processing the request (see the this.ImmediateCacheUriTemplates as an example).

you might notice there is no mapping of functions within the class (as in ASP.NET MVC and rails). that's because exysu resource classes only support a limited set of methods - Get(), Head(), Put(), Post(), Delete(), Options(). you probably recognize these names. they are the HTTP Method names. so there is no need to map code function names to a URL rule. they are done for you. as first, this might seem to be limiting, but it is not at all. in fact, it's quite liberating. by using the HTTP methods as your set of functions, you are able to quickly and easily build fully HTTP-compliant applications that scale very well and are easily cached by public caching proxies.

but that discussion is for another (future) post.

code