Request Router » History » Version 4
Version 3 (Jan Klopper, 2012-04-10 15:17) → Version 4/6 (Elmer de Looff, 2012-05-02 15:25)
h1. The Request Router
When µWeb is build around a request is sent to µWeb, the first thing so called MVC design, which often involves a routing layer that needs to be made is the decision where takes any inbound requests for pages, and how delegates them to handle it. The request router is the place where this happens. appropriate methods inside the application.
The µWeb router employed in µWeb is based on regular expressions, regexes that match urls, and delegates possibly extract various parts of the request url to hand over to the handler associated with pagemaker as arguments.
Next to the first matching expression.
Before we explain everything there routes, the router is know about routes also the startpoint for both the mod_python and handlers, an example [[standalone]] versions of how a router would look. The example given is a very stripped down version µWeb, and because of that its the handler from point where we accept various global settings that define where µWeb should load the @uweb_info@ example project: templates, where the pagemaker can be found, and how the logging should work.
h2. Some examples
<pre><code class="python">
#!/usr/bin/python
"""Some website"""
# Custom modules
import uweb
from uweb.uweb_info import pages
__author__ = 'yourname <yourname@yourdomain.nl>'
__version__ = '0.1'
PACKAGE = 'some_website'
PAGE_CLASS = pages.PageMaker
ROUTES CONFIG = (
('/static/(.*)', 'Static'),
('/(broken.*)', 'FourOhFour'),
('/haltandcatchfire', 'MakeFail'),
('/json', 'Json'),
('/text', 'Text'),
('/redirect/(.*)', 'Redirect'),
('/OpenIDLogin', '_OpenIdInitiate'),
('/OpenIDValidate', '_OpenIdValidate'),
('/ULF-Challenge', '_ULF_Challenge'),
('/ULF-Login', '_ULF_Verify'),
('/(.*)', 'Index'))
uweb.ServerSetup() '../website.conf'
</code></pre>
In the above example above, we setup a router by doing the following things happen: following:
* Firstly, we We import the @uweb@ package, since we need that to configure the webserver from uweb,
* Secondly, we We import the our module where the our Pagemaker class with our handling methods is defined (the @uweb.uweb_info.pages@ module). lives.
* @PAGE_CLASS@ is We set some copyright / author information (µWeb does not use these, buts its good python practise)
* We set the global PACKAGE variable so that holds a reference to the [[PageMaker]] subclass for your project, from where requests are handled. logging module knows what name this website has.
* @ROUTES@ is We set the global that defines PAGE_CLASS variable to the various requests class that the router understands, and directs them to the (named) method holds all of the @PAGE_CLASS@. request pages.
* Finally, @uweb.ServerSetup()@ starts We set the webserver for those cases where it runs [[StandAlone]] (and does some initial setting up for when it runs using [[Apache]])
When a request arrives, it is checked against all the defined routes. Each of the routes is a 2-tuple, with a regular expression config path, so µWeb can find and a method name (as string). The request URL is matched against load the regular expression, and if it succeeds, the method name will be resolved on the @PAGE_CLASS@. This method will then be executed, and the router will _not_ continue searching settings for a next match.
To illustrate the previous with an for example request "@/haltandcatchfire@": mysql, mongo or settings you use in your application.
# The PAGE_CLASS is instantiated into a live [[PageMaker]]
# The first After this, we will need to setup some actual routers to route tuple is inspected
#* Its regex is @'/static/(.*)'@
#* The request does *not* match incoming requests to the regex correct pages.
<pre><code class="python">
ROUTES = (
('/', 'RequestIndex'),
# The second route tuple is inspected static
('(/styles/.*)', 'Static'),
('(/js/.*)', 'Static'),
('(/media/.*)', 'Static'),
# Error handling
('(/.*)', 'RequestInvalidcommand')
#* Its regex is @'/(broken.*)'@ )
#* </code></pre>
The request does *not* match above routes do the regex following:
# The third route tuple is inspected
#* Its regex is @'/haltandcatchfire'@
#* The request *matches* * We send traffic that requests '/' to the regex
#* The associated handler method name is @'MakeFail'@ RequestIndex
#* The method @MakeFail@ is resolved on our @PageMaker@ instance, resulting * We send anything that begins with either /styles/ /js/ or /media/ to the built in @pages.PageMaker.MakeFail@
#* This method is executed and its results Static handler, from where µWeb will be sent try to read the client file including the styles/js or media part.
# Router has ended after the third inspected route * All other requests will be handled by RequestInvalidcommand, which in our case usually returns a nice 404 page.
h2. Arguments from the request string
Oftentimes, there are parts of the request string that are needed further on in the process. While it's possible to extract these in the PageMaker methods, this is inconvenient, and the router has the means to do this. As you can be seen see, every match we make in the router example above, some of regex will be a new argument on the regular expressions have capture groups defined. These capture groups are provided to the PageMaker method as positional arguments. For example: recipient method.
Requesting "@/user/elmer/edit/27@" on To make the following router:
actual server run, we do one last command:
<pre><code class="python">
PAGE_CLASS = blog.BlogPages uweb.ServerSetup()
ROUTES = (
('/user/(\w*)/edit/(\d*)', 'EditArticle'),
('/', 'Index'))
</code></pre>
Will end up calling the method @blog.BlogPages.EditArticle@ with the arguments @('Elmer', '27')@. Note that all arguments are provided as strings, type-conversion is left to the developer.
h2. Typical regexes for request matching More examples
How to use various other url formats:
* To If you want to match one or more letters, numbers, random word like characters, dashes and spaces, and possibly include a trailing / you can use something like this: @'([\w\- ]+)'@
** ([\w\- ]+)/?
* Match If you want to match multiple words, and send them as arugments the Method like this: /somecommand/userX/projectY/edit/ use the following, again with the optional trailing slashes (so that requests don't end up 404'ing because of an added slash) add: @'/?'@ slash at the end.
** /somecommand/([\w\- ]+)/([\w\-]+)/othercommand/?
* To match optional If you want to include an optional optinal page number: @'article/([\w\- ]+)/?(\d+)?'@ number after a command:
** This matches @/article/cookies_are_delicious@ /somecommand/?(\d+)?
** As well This will for example match: /somecommand, /somecommand/10 /somecommand/10/ and in both the last two send 10 as @/article/cookies_are_delicious/2@ the first argument to the method processing the request.
h2. Static files
µWeb can handle Static files from disk by itself, you just need to point the routes to the Static method, and give it the correct path where it can find the resource.
** And also @/article/cookies_are_delicious/@ – The mime-type will be discovered automatically by using the Magic libraries avialable on your server.
h2. OpenID routers
How to allow for trailing slashes that are almost certain setup routes if you want to happen use the openID module:
* ('/OpenIDLogin/?(\w+)?', '_OpenIdInitiate')
* ('/OpenIDValidate', '_OpenIdValidate')
When µWeb is build around a request is sent to µWeb, the first thing so called MVC design, which often involves a routing layer that needs to be made is the decision where takes any inbound requests for pages, and how delegates them to handle it. The request router is the place where this happens. appropriate methods inside the application.
The µWeb router employed in µWeb is based on regular expressions, regexes that match urls, and delegates possibly extract various parts of the request url to hand over to the handler associated with pagemaker as arguments.
Next to the first matching expression.
Before we explain everything there routes, the router is know about routes also the startpoint for both the mod_python and handlers, an example [[standalone]] versions of how a router would look. The example given is a very stripped down version µWeb, and because of that its the handler from point where we accept various global settings that define where µWeb should load the @uweb_info@ example project: templates, where the pagemaker can be found, and how the logging should work.
h2. Some examples
<pre><code class="python">
#!/usr/bin/python
"""Some website"""
# Custom modules
import uweb
from uweb.uweb_info import pages
__author__ = 'yourname <yourname@yourdomain.nl>'
__version__ = '0.1'
PACKAGE = 'some_website'
PAGE_CLASS = pages.PageMaker
ROUTES CONFIG = (
('/static/(.*)', 'Static'),
('/(broken.*)', 'FourOhFour'),
('/haltandcatchfire', 'MakeFail'),
('/json', 'Json'),
('/text', 'Text'),
('/redirect/(.*)', 'Redirect'),
('/OpenIDLogin', '_OpenIdInitiate'),
('/OpenIDValidate', '_OpenIdValidate'),
('/ULF-Challenge', '_ULF_Challenge'),
('/ULF-Login', '_ULF_Verify'),
('/(.*)', 'Index'))
uweb.ServerSetup() '../website.conf'
</code></pre>
In the above example above, we setup a router by doing the following things happen: following:
* Firstly, we We import the @uweb@ package, since we need that to configure the webserver from uweb,
* Secondly, we We import the our module where the our Pagemaker class with our handling methods is defined (the @uweb.uweb_info.pages@ module). lives.
* @PAGE_CLASS@ is We set some copyright / author information (µWeb does not use these, buts its good python practise)
* We set the global PACKAGE variable so that holds a reference to the [[PageMaker]] subclass for your project, from where requests are handled. logging module knows what name this website has.
* @ROUTES@ is We set the global that defines PAGE_CLASS variable to the various requests class that the router understands, and directs them to the (named) method holds all of the @PAGE_CLASS@. request pages.
* Finally, @uweb.ServerSetup()@ starts We set the webserver for those cases where it runs [[StandAlone]] (and does some initial setting up for when it runs using [[Apache]])
When a request arrives, it is checked against all the defined routes. Each of the routes is a 2-tuple, with a regular expression config path, so µWeb can find and a method name (as string). The request URL is matched against load the regular expression, and if it succeeds, the method name will be resolved on the @PAGE_CLASS@. This method will then be executed, and the router will _not_ continue searching settings for a next match.
To illustrate the previous with an for example request "@/haltandcatchfire@": mysql, mongo or settings you use in your application.
# The PAGE_CLASS is instantiated into a live [[PageMaker]]
# The first After this, we will need to setup some actual routers to route tuple is inspected
#* Its regex is @'/static/(.*)'@
#* The request does *not* match incoming requests to the regex correct pages.
<pre><code class="python">
ROUTES = (
('/', 'RequestIndex'),
# The second route tuple is inspected static
('(/styles/.*)', 'Static'),
('(/js/.*)', 'Static'),
('(/media/.*)', 'Static'),
# Error handling
('(/.*)', 'RequestInvalidcommand')
#* Its regex is @'/(broken.*)'@ )
#* </code></pre>
The request does *not* match above routes do the regex following:
# The third route tuple is inspected
#* Its regex is @'/haltandcatchfire'@
#* The request *matches* * We send traffic that requests '/' to the regex
#* The associated handler method name is @'MakeFail'@ RequestIndex
#* The method @MakeFail@ is resolved on our @PageMaker@ instance, resulting * We send anything that begins with either /styles/ /js/ or /media/ to the built in @pages.PageMaker.MakeFail@
#* This method is executed and its results Static handler, from where µWeb will be sent try to read the client file including the styles/js or media part.
# Router has ended after the third inspected route * All other requests will be handled by RequestInvalidcommand, which in our case usually returns a nice 404 page.
h2. Arguments from the request string
Oftentimes, there are parts of the request string that are needed further on in the process. While it's possible to extract these in the PageMaker methods, this is inconvenient, and the router has the means to do this. As you can be seen see, every match we make in the router example above, some of regex will be a new argument on the regular expressions have capture groups defined. These capture groups are provided to the PageMaker method as positional arguments. For example: recipient method.
Requesting "@/user/elmer/edit/27@" on To make the following router:
actual server run, we do one last command:
<pre><code class="python">
PAGE_CLASS = blog.BlogPages uweb.ServerSetup()
ROUTES = (
('/user/(\w*)/edit/(\d*)', 'EditArticle'),
('/', 'Index'))
</code></pre>
Will end up calling the method @blog.BlogPages.EditArticle@ with the arguments @('Elmer', '27')@. Note that all arguments are provided as strings, type-conversion is left to the developer.
h2. Typical regexes for request matching More examples
How to use various other url formats:
* To If you want to match one or more letters, numbers, random word like characters, dashes and spaces, and possibly include a trailing / you can use something like this: @'([\w\- ]+)'@
** ([\w\- ]+)/?
* Match If you want to match multiple words, and send them as arugments the Method like this: /somecommand/userX/projectY/edit/ use the following, again with the optional trailing slashes (so that requests don't end up 404'ing because of an added slash) add: @'/?'@ slash at the end.
** /somecommand/([\w\- ]+)/([\w\-]+)/othercommand/?
* To match optional If you want to include an optional optinal page number: @'article/([\w\- ]+)/?(\d+)?'@ number after a command:
** This matches @/article/cookies_are_delicious@ /somecommand/?(\d+)?
** As well This will for example match: /somecommand, /somecommand/10 /somecommand/10/ and in both the last two send 10 as @/article/cookies_are_delicious/2@ the first argument to the method processing the request.
h2. Static files
µWeb can handle Static files from disk by itself, you just need to point the routes to the Static method, and give it the correct path where it can find the resource.
** And also @/article/cookies_are_delicious/@ – The mime-type will be discovered automatically by using the Magic libraries avialable on your server.
h2. OpenID routers
How to allow for trailing slashes that are almost certain setup routes if you want to happen use the openID module:
* ('/OpenIDLogin/?(\w+)?', '_OpenIdInitiate')
* ('/OpenIDValidate', '_OpenIdValidate')