Table Of Contents

Routing Requests According to HTTP Request Method


The module code listed below is also attached to this page and can be downloaded here:


The decorator included below enables TurboGears applications to automatically route requests to functions based on the HTTP method type (GET, POST, PUT, and DELETE).


Here is a quick synopsis of how you would use the code below in your controller class:

from turbogears import controllers
from httpmethodrouter import *

class MyController(controllers.Controller):

    def edit(self, *p, **kwp):

    def edit_GET(self, *p, **kwp):
       """Handles all edit GET requests."""

    def edit_POST(self, *p, **kwp):
        """Handles all edit POST requests."""

    def edit_PUT(self, *p, **kwp):
        """Handles all edit PUT requests."""

    def edit_DELETE(self, *p, **kwp):
        """Handles all edit DELETE requests."""

Please see the code below for more information about the http_method_router decorator.


# -*- coding: UTF-8 -*-

import cherrypy
from turbogears.decorator import decorator

__all__ = ['http_method_router']

def http_method_router(default=None, alt_mappings=None):
    """Routes requests based on the http request type (GET, POST, PUT, DELETE).

    By default, the http_method_router will attempt to forward the request
    to the corresponding ``<function_name>_<http_method>`` function.
    For example, if a function named "edit" is decorated with the
    ``http_method_router``, then all GET requests will be routed to the
    ``edit_GET`` function, all POST requests to the ``edit_POST`` function, etc.

    If a function cannot be matched to the request, then the router will
    first check for a value in the default parameter.  If this is a valid
    value, then the corresponding function will be called.  If no default value
    is specified, then an attempt will be made to route the request to the
    ``<function_name>_GET`` function.  If that function does not exist, then a
    ``cherrypy.NotFound`` exception will be raised.

    If you do not want to use the default ``<function_name>_<http_method>``
    behavior, then alternate mappings can be specified by passing in a
    dict of ``<http_method>`` to ``function_name`` values in the
    ``alt_mappings`` parameter.

    See the examples below for more information.


        The full name of the default function to call
        if a match cannot be found.  If left empty,
        the ``<func_name>_GET`` function will be called.
        A dictionary of alternate http method->function
        name mappings.  The keys for the dictionary
        should be the relevant http method strings
        (GET, POST, PUT, DELETE).

    Example 1: Default Behavior

    The example below works as follows:

    1. The target method, ``edit``, is decorated with the ``http_method_router``

    2. When ``edit`` is called, it will route all GET requests to ``edit_GET``,
       and all POST requests to ``edit_POST``.

    3. If an unmapped method is used (PUT or DELETE in this case), then
       ``edit_GET`` will be called by default. To change the default behavior,
       add the ``default`` parameter to the decorator::


    Sample Code 1

        def edit(self, *args, **kwargs):

        def edit_GET(self, *args, **kwargs):

        def edit_POST(self, *args, **kwargs):

    Example 2: Alternate mappings

    The example below works as follows:

    1. The ``alt_mappings`` parameter is specified with the mappings for
       the GET and POST requests.

    2. All ``edit GET`` requests are routed to the ``show`` function, and
       all ``edit POST`` requests are routed to the ``update`` function.

    3. In this case, since no other mappings are declared, and no
       default method was specified, all PUT and DELETE requests
       will cause a ``cherrypy.NotFound`` exception to be raised.

    Sample Code 2

        @http_method_router(alt_mappings=dict(GET='show', POST='update'))
        def edit(self, *args, **kwargs):

        def show(self, *args, **kwargs):

        def update(self, *args, **kwargs):


    def entangle(fn):
        def method_router(func, self, *args, **kwargs):
            if callable(func):
                name = func.__name__
                method = cherrypy.request.method
                target = name + "_" + method
                alternate = None

                if isinstance(alt_mappings, dict) and \
                    alternate = alt_mappings[method]
                    if(hasattr(self, alternate) and
                        return self.__getattribute__(alternate)(*args, **kwargs)

                if hasattr(self, target) and \
                    return self.__getattribute__(target)(*args, **kwargs)
                elif(default and
                     hasattr(self, default) and
                    return self.__getattribute__(default)(*args, **kwargs)
                elif hasattr(self, name + "_GET"):
                    return self.__getattribute__(name+"_GET")(*args, **kwargs)
                    raise cherrypy.NotFound()

                raise cherrypy.NotFound()
        return decorator(method_router)(fn)
    return entangle