Request Router » History » Version 6
Arjen Pander, 2015-03-12 16:59
1 | 1 | Jan Klopper | h1. The Request Router |
---|---|---|---|
2 | 1 | Jan Klopper | |
3 | 4 | Elmer de Looff | When a request is sent to µWeb, the first thing that needs to be made is the decision where and how to handle it. The request router is the place where this happens. The router employed in µWeb is based on regular expressions, and delegates the request to the handler associated with the first matching expression. |
4 | 1 | Jan Klopper | |
5 | 6 | Arjen Pander | Before we explain everything there is to know about routes and handlers, an example of how a router would look. The example given is a very stripped down version of the handler from the @uweb_info@ example project: |
6 | 1 | Jan Klopper | |
7 | 1 | Jan Klopper | <pre><code class="python"> |
8 | 1 | Jan Klopper | import uweb |
9 | 4 | Elmer de Looff | from uweb.uweb_info import pages |
10 | 1 | Jan Klopper | |
11 | 1 | Jan Klopper | PAGE_CLASS = pages.PageMaker |
12 | 4 | Elmer de Looff | ROUTES = ( |
13 | 4 | Elmer de Looff | ('/static/(.*)', 'Static'), |
14 | 4 | Elmer de Looff | ('/(broken.*)', 'FourOhFour'), |
15 | 4 | Elmer de Looff | ('/haltandcatchfire', 'MakeFail'), |
16 | 4 | Elmer de Looff | ('/json', 'Json'), |
17 | 4 | Elmer de Looff | ('/text', 'Text'), |
18 | 4 | Elmer de Looff | ('/redirect/(.*)', 'Redirect'), |
19 | 4 | Elmer de Looff | ('/OpenIDLogin', '_OpenIdInitiate'), |
20 | 4 | Elmer de Looff | ('/OpenIDValidate', '_OpenIdValidate'), |
21 | 4 | Elmer de Looff | ('/ULF-Challenge', '_ULF_Challenge'), |
22 | 4 | Elmer de Looff | ('/ULF-Login', '_ULF_Verify'), |
23 | 4 | Elmer de Looff | ('/(.*)', 'Index')) |
24 | 4 | Elmer de Looff | |
25 | 4 | Elmer de Looff | uweb.ServerSetup() |
26 | 1 | Jan Klopper | </code></pre> |
27 | 1 | Jan Klopper | |
28 | 4 | Elmer de Looff | In the example above, the following things happen: |
29 | 4 | Elmer de Looff | * Firstly, we import the @uweb@ package, since we need that to configure the webserver from |
30 | 4 | Elmer de Looff | * Secondly, we import the module where the class with our handling methods is defined (the @uweb.uweb_info.pages@ module). |
31 | 4 | Elmer de Looff | * @PAGE_CLASS@ is the global that holds a reference to the [[PageMaker]] subclass for your project, from where requests are handled. |
32 | 4 | Elmer de Looff | * @ROUTES@ is the global that defines the various requests that the router understands, and directs them to the (named) method of the @PAGE_CLASS@. |
33 | 4 | Elmer de Looff | * Finally, @uweb.ServerSetup()@ starts the webserver for those cases where it runs [[StandAlone]] (and does some initial setting up for when it runs using [[Apache]]) |
34 | 1 | Jan Klopper | |
35 | 4 | Elmer de Looff | When a request arrives, it is checked against all the defined routes. Each of the routes is a 2-tuple, with a regular expression and a method name (as string). The request URL is matched against 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 for a next match. |
36 | 1 | Jan Klopper | |
37 | 4 | Elmer de Looff | To illustrate the previous with an example request "@/haltandcatchfire@": |
38 | 1 | Jan Klopper | |
39 | 4 | Elmer de Looff | # The PAGE_CLASS is instantiated into a live [[PageMaker]] |
40 | 4 | Elmer de Looff | # The first route tuple is inspected |
41 | 4 | Elmer de Looff | #* Its regex is @'/static/(.*)'@ |
42 | 4 | Elmer de Looff | #* The request does *not* match the regex |
43 | 4 | Elmer de Looff | # The second route tuple is inspected |
44 | 4 | Elmer de Looff | #* Its regex is @'/(broken.*)'@ |
45 | 4 | Elmer de Looff | #* The request does *not* match the regex |
46 | 4 | Elmer de Looff | # The third route tuple is inspected |
47 | 4 | Elmer de Looff | #* Its regex is @'/haltandcatchfire'@ |
48 | 4 | Elmer de Looff | #* The request *matches* the regex |
49 | 4 | Elmer de Looff | #* The associated handler method name is @'MakeFail'@ |
50 | 4 | Elmer de Looff | #* The method @MakeFail@ is resolved on our @PageMaker@ instance, resulting in @pages.PageMaker.MakeFail@ |
51 | 4 | Elmer de Looff | #* This method is executed and its results will be sent to the client |
52 | 4 | Elmer de Looff | # Router has ended after the third inspected route |
53 | 1 | Jan Klopper | |
54 | 4 | Elmer de Looff | h2. Arguments from the request string |
55 | 1 | Jan Klopper | |
56 | 4 | Elmer de Looff | 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 can be seen in the router example above, some of the regular expressions have capture groups defined. These capture groups are provided to the PageMaker method as positional arguments. For example: |
57 | 4 | Elmer de Looff | |
58 | 4 | Elmer de Looff | Requesting "@/user/elmer/edit/27@" on the following router: |
59 | 4 | Elmer de Looff | |
60 | 1 | Jan Klopper | <pre><code class="python"> |
61 | 4 | Elmer de Looff | PAGE_CLASS = blog.BlogPages |
62 | 4 | Elmer de Looff | ROUTES = ( |
63 | 4 | Elmer de Looff | ('/user/(\w*)/edit/(\d*)', 'EditArticle'), |
64 | 4 | Elmer de Looff | ('/', 'Index')) |
65 | 1 | Jan Klopper | </code></pre> |
66 | 1 | Jan Klopper | |
67 | 4 | Elmer de Looff | 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. |
68 | 1 | Jan Klopper | |
69 | 4 | Elmer de Looff | h2. Typical regexes for request matching |
70 | 4 | Elmer de Looff | |
71 | 1 | Jan Klopper | How to use various other url formats: |
72 | 1 | Jan Klopper | |
73 | 4 | Elmer de Looff | * To match one or more letters, numbers, dashes and spaces, use this: @'([\w\- ]+)'@ |
74 | 4 | Elmer de Looff | * Match optional trailing slashes (so that requests don't end up 404'ing because of an added slash) add: @'/?'@ |
75 | 4 | Elmer de Looff | * To match optional an optional page number: @'article/([\w\- ]+)/?(\d+)?'@ |
76 | 4 | Elmer de Looff | ** This matches @/article/cookies_are_delicious@ |
77 | 4 | Elmer de Looff | ** As well as @/article/cookies_are_delicious/2@ |
78 | 4 | Elmer de Looff | ** And also @/article/cookies_are_delicious/@ – to allow for trailing slashes that are almost certain to happen |
79 | 5 | Elmer de Looff | |
80 | 5 | Elmer de Looff | h2. Unicode notice |
81 | 5 | Elmer de Looff | |
82 | 5 | Elmer de Looff | Where available (and necessary), path strings will be decoded from UTF8 in the [[Request]] object. The regular expressions for the router are also evaluated with full support for Unicode. This means that a route-regex @'\w+'@ will match 'café' (the French for 'coffee'), despite the non-ASCII characters in that string. |