Simple REST-ful (-ish) exposure of Python APIs

After having written code to expose APIs through RESTful web services a couple of times, I've decided to do it once more, only this time I won't get paid, I won't have deadlines, I'll write it so I'll never have to write it again, and I'll make it available as open source.

Problem is, I'm a lazy, lazy person, and have not been able to muster the energy to actually get writing, which leads me to this blog post - since I've not been updating the blog as I should either, I'll kill two projects with one meeting and make the actual development process open as well, as a series of blog posts and a repository at BitBucket.

For someone else to be able to follow the work, I obviously have to nail down what the goal of this exercise is:


    * Create a tool that can expose a Python API in a RESTish fashion
    * The API itself must not have to know about the tool
    * It must run on at least CherryPy and two other webapp frameworks TBD (no, not Django)
    * It must handle HTTP errors
    * It must be able to encode data into JSON before returning it
    * It must run on Python 3.2+
    * It must not care what the proper definition of RESTful is

In addition, some good-to-haves:


    * It may make linking between resources easier (if feasible)
    * It may be able to use other data formats than JSON
    * It may run on Python 2.7

Because I enjoy working with CherryPy since it's very good at staying out of my way, I'll start out writing for CherryPy and then generalize from there. Just to get started, I have created a minimal CherryPy app to work from, even though I'll split the tool from the framwork (or the REST framework from the web framework?) later. The entire code looks like this:


    import cherrypy

    def requesthandler(*pathargs, **kwargs):
        cherrypy.response.status = "500 Server Error"
        return "Not implemented"


    class PyRest(object):

        def index(self, *args, **kwargs):
            return requesthandler(*args, **kwargs)
        index.exposed = True


    CONF = {
        'global': {
            'server.`socket`_host': '0.0.0.0',
            'server.`socket`_port': 8888,
        }
    }


    if `__name_`_ == '`__main_`_':
        ROOT = PyRest()
        cherrypy.quickstart(ROOT, '/', CONF)

    def application(environ, `start`_response):
      cherrypy.tree.mount(PyRest(), '/', None)
      return cherrypy.tree(environ, `start`_response)
comments powered by Disqus