Skip to content
renzon edited this page Oct 17, 2013 · 5 revisions

The first issue a web framework must solve is the url routing. Most technologies has a configuration file, like web.xml on Java or app.yaml on GAE Python, routing urls to respective backend code. It´s possible build entire applications relying on this configuration, but it has some problems:

  • Changes on code location lead to changes on configuration
  • Every new page need to be mapped on configuration

So using configuration will lead you on a forever growing configuration file and changes on it can be very awful.

Convention over Configuration

Once the one configuration file can be a bad approach for mediun/big apps, some frameworks build a layer inside them to delegate the configuration for something else, like a set of another config files or configuration inside the backend code.

On Zenwarch the principle "Convention over Configuration" is heavily used. So we are going to solve the url routing issue with a simple convention inspired on PHP and REST:

Handler Function Respective URL
home.index /
user.index /user
user.save /user/save
product.form.edit(name=foo,price=32) /product/form/edit/foo/32 or /product/form/edit?name=foo&price=32

So the configuration is a convention search for a module's function. The module lives inside a common package (default is web). So given a function web.user.save it will be routed from /user/save. To build the the url you just need to replace "." for "/" and remove the "web" from the function notation. On other hand, to construct the function from an url, like /package/module/function/ you just need replace "/" for "." and add the "web" before this string: web.package.module.function.

If you don´t have a function name on your url, the convention is search for an "index" function inside de module. If you don´t have module name, the convention is search for a module named "home" and a function named "index" inside it.

Module zen.router.py

router.py is the module to accomplish the above convention. It has 2 main functions:

to_handler function

The to_handler function returns a tuple (function, params_list) from a path.

Let´s write a script:

def save(name,age):
        pass

Supose the project organized as follows:

  web
     user
         save

Running the code:

from zen import router

print router.to_handler("/user/save/john/32")

The output is:

(<function save at 0x2580938>, ['john', '32'])

Process finished with exit code 0

The information extracted with this function can be used to execute the desired function. For GAE projects there is already a handler, convention.py, using this module to route urls calls in handler´s functions execution. So using this function will not be often if you use this general handler, but is important konw it if you want port Zenwarch in another Python plataform, like Django.

to_path function

When writing your app, it will be very common referencing links. The most directly way to do this would be put the ancor directly on html:

...some html page...

<a href="/user/save/jonh/32">Save John</a>

The problem with this approach is: if you decide to change one name on your backend, all the links referring to this url will be broken. To avoid this problem, would be nice to have the links following the convention so if the Python script is refactored, so the link automatically change.

With this idea in mind, the to_path function was created. Let´s build the url from our page based on this function:

from zen import router
from web.user import save

print router.to_path(form.save,"john",32)

The output is:

/user/save/john/32

So instead of writing static links in your pages, you can build the links based on function´s handler and passing this value as a variable. In this way, when you refactor your code all the links will be automatically changed.

Next section will show how to use router module to handle web requests: Requests