Skip to content

ATOM-style REST endpoints with tipfy/werkzeug

I’m very used to and (somewhat) pleased with how Routes let’s you set up REST endpoints, so I was very irked to discover that Tipfy does not support the notion of a resource.

Routes will let you do something like

map = routes.Mapper(...)
map.resource('teapot' , 'teapots')

which will create a mapping like

GET     /teapots    -> controllers.teapots.TeapotController.get()
GET     /teapots/1  -> controllers.teapots.TeapotController.show(1)
PUT     /teapots/1  -> controllers.teapots.TeapotController.edit(1)
POST    /teapots    -> controllers.teapots.TeapotController.create()
DELETE  /teapots/1  -> controllers.teapots.TeapotController.delete(1)

The way Tipfy dispatch works, however, is by calling the http request method attribute on the matched handler

handler = request.rule.handler
#...
method = request.method.lower().replace('-', '_')
return handler(self, request)(method, **request.rule_args)

As you can see, this doesn’t allow for a “show” method, etc. on your handler.

The solution I’m going with for now is a base class called RestHandler:

class RestHandler(RequestHandler):
 
    def __call__(self, method, *args, **kwargs):
        """Translate HTTP methods to ATOM Publishing Protocol-esque endpoints"""
 
        try:
            if method == 'get':
                if len(args) or len(kwargs):
                    return self.show(*args, **kwargs)
                else:
                    return self.get()
 
            if method == 'post':
                return self.create()
            if method == 'put':
                return self.edit()
        except AttributeError, e:
            raise werkzeug.exceptions.MethodNotAllowed(method)
 
        return super(RestHandler, self).__call__(method, *args, **kwargs)

Your handlers can inherit from this to implement something similar to the ATOM Publishing Protocol

Update: Ian Eure has done something similar to Decoroute, which you might want to check out if you prefer using decorators