Web Oriented Object Framework

User Guide (Version 0.5b4)

Woof!
User Guide (Version 0.5b4)

URL routes

There may be situations where the desired URL format does not satisfy the assumptions behind Woof!'s default URL mapping. For example, you may want the URL

  http://www.mycompany.com/support/ticket/display/123

to display the page corresponding to support ticket #123. This URL cannot be mapped to the appropriate controller by the default URL mapping since the mapping algorithm expects the action method to be the last component in the URL. In the above case the last component is actually the ticket number. Woof! allows such URL's to be handled through the definition of URL routes. Woof! will first check these route definitions for a match before falling back to the default mapping algorithm.

Route definition file

Woof! reads the URL route definitions from the file routes.cfg in the config subdirectory. This file is is expected to contain Tcl code and is executed in a temporary safe Tcl interpreter. The file may contain any Tcl code compatible with safe interpreters. A route is defined through the curl command which has the following format:

curl CURL ACTIONS PURL

An example of a route is

curl /finance/companies {profile quote} symbol

This route will match application URL paths of the form /finance/companies/quote/csco or /finance/companies/profile/BRK.A and invoke the quote or profile action in the controller finance::Companies passing it a parameter symbol containing csco and BRK.A respectively. More examples are given below.

The CURL argument specifies the relative URL for the controller and may include a module path but does not include Woof! application root. The last component is the controller name and any prior components specify the module. For example, /x/y/z in this component would be treated as the controller class x::y::Z or equivalently the controller z in module x y.

ACTIONS specifies the action methods for which the definition is applicable. This may be a list of action names, an empty list which indicates the definition applies to all actions, or a string beginning with implicit: (for example, implicit:display. In this last case, the URL is treated as not having an action component and any remaining components after the controller are matched against parameter definitions. The string after the implicit: prefix is treated as the action method to invoke. An example is shown later.

PURL is a URL path that defines additional parameters that are supplied in the rest of the URL. Note these are not the explicit parameters sent as part of a query or form post but rather additional parameters that may be merged with them. Each component in this PURL should have the format PARAMNAME:REGEXP:DEFAULT where PARAMNAME specifies the name of the parameter, REGEXP, if not empty, specifies a regular expression that the URL component should match, and DEFAULT is the default value to be used if the URL component is missing. DEFAULT is actually passed through the Tcl subst command with -nocommands options hence variable definitions and backslash sequences can be used. However, characters that are special to Tcl will need to be escaped.

In addition, the PARAMNAME field of the last path component in PURL may begin with a * character in which case the corresponding parameter is a list of all remaining URL component values.

Note that any : character in a default value should be encoded using \u Tcl escape sequences else it will be treated as the start of the default value as opposed to be embedded in it.

Route matching

Routes defined through the curl command are stored in the order the corresponding commands are executed, which is generally the order in which they occur in the file. Incoming requests are matched against the routes in this order and the first matching route is selected.

The matching algorithm first strips off the protocol scheme, host and port (if any) from the URL. The URL root of the Woof! application is also removed. The rest of the URL is then matched against each route definition with the first matching definition being selected.

For a match to succeed, all three portions of the definition - the controller URL, the action method name, and URL path embedded parameters (as opposed to query parameters) - must match.

Examples

These examples assume the host and application root URL http://www.mycompany.com/support/ is stripped off (support being the application root) leaving behind a relative URL that is matched against routes.

Route: simple route

curl /ticket index

The relative URL /ticket/index would successfully match against this route and presumably show a list of support tickets. The action index in class Ticket would be invoked. Note the URL /ticket/index/123 does not match this route as it has an additional URL component. In fact, this route definition is redundant since the default URL mapping behaviour will give the same result.

Route: using parameters

curl /ticket display id

The relative URL /ticket/display/123 would successfully match against this route. The action display in class Ticket would be invoked. The parameter with name id with a value of 123 would be passed to the method using the standard parameter passing mechanism described in the Implementing actions chapter.

Route: multiple actions

curl /ticket {display edit} id

This is similar to the previous route except that two actions are listed so both /ticket/display/123 and /ticket/edit/123 will match.

Route: matching on parameter syntax

curl /ticket display {id:[[:digit:]]+:}

The problem with the route in the previous examples was that although /ticket/display/123 would successfully match, so would the URL /ticket/display/abc, something that is probably undesired. Adding a regular expression to the parameter definition ensures that only numeric strings will match the parameter component for id. The URL /ticket/display/abc would therefore not match the route.

The relative URL /ticket/display would also not match the route definition since no parameter is specified.

Route: using default parameter values

curl /ticket display {id:[[:digit:]]+:1}

Route: using implicit actions

curl /ticket implicit:display {id:[[:digit:]]+:}

You may also choose the implicit action method selection mechanism so that the display component is not required in the URL. So with the route definition in this example, the relative URL /ticket/123 would result in same invocation of the display action method as above. Note that if you want URL's of the form shown in the previous examples as well, both route definitions would need to be in place as this route will not match the URL's in the previous example.

Route: parameter with list values

curl /ticket display {*id:[[:digit:]]+:}

Prefixing a parameter with the * character causes the parameter to collect the entire remaining portion of the URL as a list value. So in this example, relative URL's such as /ticket/display/12 and /ticket/display/12/34/56 would both be accepted, with the id parameter set to lists {12} and {12 34 56} respectively.

Example: using Tcl code in route definition files

set year_regex {[[:digit:]]{4}}
set month_regex {[[:digit:]]{1,2}}
set day_regex {[[:digit:]]{1,2}}
set date_params year:${year_regex}:/month:${month_regex}:/day:${day_regex}:
foreach controller {blog article} {
    curl "/$controller" implicit:display $date_params
}

This Tcl fragment in a route definition file would set up two routes which would match URL's of the form /blog/2009/1/21 or /article/2009/1/21 and invoke the display action on the Blog or Article controllers respectively.