Go to page content

Understanding resource dispatch rules

A walk through of the syntax and semantics of dispatch rules.

Why

Dispatch rules can be confusing. That inspired me to dig in and figure it out and document it more clearly.

Assumptions

Readers are expected to have a basic understanding of Erlang and the concept of web routing in general.

How

A dispatch rule works as follows:

{RuleName, UrlPattern, ResourceModule, ResourceArgs}
RuleName = atom()
PathSpec = [PathSegmentSpec]
PathSegmentSpec = StaticMatch | Wildcard | Variable
StaticMatch = string()
Wildcard = '*'
PathVariable = atom()
ResourceModule = atom()
ResourceArgs = [{Key,Value}]

All PathVariables in the matching rule are made available to the resource through z_context . The ResourceArgs proplist is passed to ResourceModule:init/1 .

PathVariables are part of the request-scope configuration of ResourceModule . Things like the ID , name or category of a page being requested can be gathered effectively here. Judicious use of PathVariables can substantially reduce the number of dispatch rules while making them easier to read.

ResourceArgs is the rule-scope configuration of ResourceModule. It makes it possible to reuse a well-designed resource module in many dispatch rules with different needs. ResourceArgs is effective for establishing implementation details like the template to be used, whether or not to do caching and where to load static resources from.

AFAIK Zotonic dispatch rules are identical to Webmachine's with the addition of RuleName. Webmachine's dispatch rules are described in detail at http://webmachine.basho.com/dispatcher.html .

How about some examples folks?

Here is the dispatch rule for the home page in mod_base:

{home, [], resource_template, [ {template, "home.tpl"} ]}

This is a pretty simple rule. It renders responses to the root path using the home.tpl template file.

Building on this we could make many rules for pages in our website:

{links, ["links"], resource_template, [ {template, "links.tpl"} ]},
{about, ["about"], resource_template, [ {template, "about.tpl"} ]},
{blog1, ["this-is-a-blog"], resource_template, [ {template, "this-is-a-blog.tpl"} ]},
... 100s more

That quickly becomes very repetitive and requires content authors to know how how to write ErlyDTL templates. Double fail.

Here is the dispatch for the blog homepage from the blog site skeleton:

{home, [], resource_template, [ {template, "home.tpl"}, {id, page_home} ]}

This is also a pretty simple rule. It redirects the root path to the home.tpl template, but also sets the context variable id which is available to home.tpl during rendering. In general the variable id can be used for anything, but Zotonic conventionally uses it for an RSC (aka Page) id or unique name.

Whoop-de-doo, we have replaced a static template with a static reference to a CMS page. Actually, that's kind of a big deal: now our content authors can alter the home page copy at their discretion.

Wait a second! All those repetitive rules for each page can now use CMS pages too:

{links, ["links"], resource_template, [ {template, "links.tpl"}, {id, page_links] },
{about, ["about"], resource_template, [ {template, "about.tpl"}, {id, page_about} ]},
{blog1, ["this-is-a-blog"], resource_template, [ {template, "this-is-a-blog.tpl"}, {id, this_is_a_blog} ]},
... 100s more

That was unbelievably painful and didn't buy us a whole lot more than clarity on future sleep plans :( Can't we do better? We certainly can :)

Logically there is some kind of relationship between the URL on the visitor's browser and the page they are looking at. Dispatch rules support PathVariables which allows us to extract this relationship into resource parameters. How do we go about using them?

Right off the bat we could structure URL paths as /cat/id/slug. This gives us the advantage of being able to easily identify the category and the page within it as well as providing an SEO benefit by having the slug in the URL.

So now we can reduce hundreds of rules to one per category:

{info, ["info", id, slug], resource_template, [ {template, "info.tpl"}, {cat, info} ],
{blog, ["blog", id, slug], resource_template, [ {template, "blog.tpl"}, {cat, blog} ],
... several others

That is a massive savings in configuration over the last iteration we made.

Now the Zotonic zinger :D Look at http://code.google.com/p/zotonic/source/browse/modules/mod_base/dispatch

{page, ["page", id      ], resource_page, [ {template, {cat, "page.tpl"}} ]},
{page, ["page", id, slug], resource_page, [ {template, {cat, "page.tpl"}} ]}, 

In reality you don't need dispatch rules for pages or categories. All you need are templates like page.article.tpl and use of catinclude tags rather than straight includes and you have a fully convention over configuration setup for Zotonic.

However, one-off pages that need special template behaviors are still a good case for site-specific dispatch. On the other hand, if those pages need CMS-editable copy then you are just as well to create a category for each such page and use the page.cat.tpl approach. A dispatch rule bound to a unique name on the copy Page is another option, but it requires more thought and involves greater risk.

Overall Dispatch Rules are IMHO a last resort for site builders and really better left to module or core developers.

I managed to nuke my staging environment several times with dispatch mistakes and I'd rather not admit to the number of hours I spent debugging them. Please reach for Dispatch Rules only when you really need them :)

Further Reading

Advanced Dispatch URL Matching

Troubleshooting

There are no troubleshooting steps available for this guide.  Please provide any you have learned in the comments below or on the Zotonic Users Group.

This page is part of the Zotonic documentation, which is licensed under the Apache License 2.0.