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

Written by fredrik

6 december, 2012

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:

Listing 1.

* 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:

Listing 1.

* 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)

You May Also Like…

0 kommentarer