(A little meditation from
my blog.)
The most fun for me when building a new web framework is always the dispatcher design.
Thats one of the main reasons why
Mojo is completely dispatcher agnostic.
Now you might be asking "WTF is a dispatcher?".
It is the part of your framework that maps incoming requests to the actual code that builds the response for it.
A very naive way of doing this would be a simple list of paths with classes and methods mapped to them.
/foo/bar/index -> Foo::index()
/test123.html -> Bar::default()
/cookies/list/fresh -> Cookies::list()
Every web framework out there has their own way of doing this, they all have advantages and disadvantages.
Catalyst 5 - Perl
Lets start with my good old
Catalyst 5.
Meta data is kept close to the code which makes initial development easier, but for debugging you depend very much on good log output.
Changing paths later on can be painful, and using attributes is also very tricky because the Perl api for them sucks, it can look quite good though if used right.
# /foo/bar/index
package Foo::Bar;
sub index : Relative { ... }
# /test123.html
package Foo::Bar;
sub test : Path('/test123.html') { ... }
# /cookies/list/fresh
package Cookies;
sub list : Relative Args(1) { ... }
Servlets 3.0 - Java
Servlets 3.0 will do something similar with annotations. (I'm not going to give you full examples here because...well...it's Java and ugly as hell)
@Servlet(urlMappings={"/foo", "/bar"})
public class ControllerWithAnnotations {
@GET
public void handleGet(HttpServletRequest req, HttpServletResponse
+res) { ... }
}
Jifty - Perl
For quite some time i was a big fan of declarative dispatchers like the
Jifty one.
Meta data and code are once again close together, but you have to use a full blown domain specific language.
You can't use basic Perl features like inheritance and need to reinvent a lot.
The flow is easier to follow than in Catalyst though without using log output.
# /foo/bar/index
on 'foo/bar/index' => do { ... }
# /test123.index
on 'test123.html' => do { ... }
# /cookies/list/fresh
on '/cookies/list/*' => do { ... }
Catalyst 4 - Perl
Fun fact, we nearly built a declarative dispatcher for
Catalyst 4, a long time before it was cool. :)
__PACKAGE__->action('/foo/bar/index' => sub { ... });
Ruby on Rails - Ruby
Ruby on Rails originally started using a static "/controller/action/args" mapping with Apache's
mod_rewrite in front of it.
To get rid of the Apache dependency they've invented one of the imo coolest dispatcher concepts out there called Routes.
Routes separate meta data and code completely, so you can use all the basic language features in your code.
For easy initial development you start with a simple default route like ":controller/:action/:id" and later move on to more complicated url mappings.
# /foo/bar/index
map.connect 'foo/bar/index', :controller => "foo", :action => "index"
# /test123.html
map.connect 'test123.html', :controller => "foo", :action => "test"
# /cookies/list/fresh
map.connect ':controller/:action/:quality', :controller => "cookies",
+:action => "list",
:quality => "fresh", :requirements => { :quality => /\w+/ }
Most interesting for me is the ability to reverse the route and generate urls from the pattern.
<%= link_to "Fresh Cookies", :controller => "cookies", :action => "lis
+t", :quality => "fresh" %>
Merb - Ruby
Merb uses an alternative Routes implementation, with a lot of cool new ideas.
# /foo/bar/index
r.match("/foo/bar/index").to(:controller => "foo", :action => "index")
# /test123.html
r.match("/test123.html").to(:controller => "foo", :action => "test")
# /cookies/list/fresh
r.match(%r[^/cookies/list/(\w+)$]).to(:controller => "cookies", :actio
+n => "list", :quality => 'path[1]')
Django - Python
The prize for the ugliest dispatcher goes to Python's
Django, which uses plain old regex for everything.
urlpatterns = patterns('',
(r'^foo/bar/index$', 'foo.views.index'),
(r'^test123\.html$', 'foo.views.test'),
(r'^cookies/list/(\w+)$', 'cookies.views.list'),
)
Mojolicious - Perl
For
Mojolicious i'll be using a Perl-ish Routes implementation with some
Catalyst goodness added.
More about that in my next article. ;)
# /foo/bar/index
$r->route('/foo/bar/index')->to(controller => 'foo', action => 'index'
+);
# /test123.html
$r->route('/test123.html')->to(controller => 'foo', action => 'test');
# /cookies/list/fresh
$r->route('/:controller/:action/:quality', quality => qr/\w+/)
->to(controller => 'cookies', action => 'list', quality => 'fresh');
$c->url_for(controller => 'cookies', action => 'list', quality => 'fre
+sh');
Note that this was just a very basic overview, all frameworks have much more features than i've shown here.
But i hope it will help all you future framework developers,
building dispatchers is fun, get Mojo and start today!
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
Read Where should I post X? if you're not absolutely sure you're posting in the right place.
Please read these before you post! —
Posts may use any of the Perl Monks Approved HTML tags:
- a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
| |
For: |
|
Use: |
| & | | & |
| < | | < |
| > | | > |
| [ | | [ |
| ] | | ] |
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.