JavaScript, PostGIS, Python

A simple CherryPy RESTful JSON server

I have recently been working with CherryPy. Although it seems very powerful, it is quite hard to find simple and clear online examples for some things. In this case I wanted to set up a RESTful server that can accept POST requests containing JSON/GeoJSON, and return JSON/GeoJSON. For testing I set up a small web page that sends the request and displays the response.

If you are doing Python or web development, you may be interested in my Windows Dev Stack, which describes my development environment from high level technologies down to specific apps, and how they all work together.

Gotchas

As with many web things there are a lot of layers, and it is tricky to debug exactly what is going wrong when it doesn’t work. Some things to watch out for:

  • CORS: although you see CORS errors in the browser, it is actually the server (i.e. CherryPy) that has to enable CORS – in this case you have to explicitly allow the origin of the request
  • formatting: data must be properly formatted JSON strings (in both directions), there are tools to help with this

The server code

The following code is stripped down to a minimal working configuration. To expand it further you will need to read the docs and hunt around for more examples! Feel free to comment below if you would like to contribute.

The POST method accepts some JSON, and returns the incoming data along with some of its own.

import cherrypy
import json

class DataView(object):
    exposed = True

    @cherrypy.tools.accept(media='application/json')

    def POST(self):
        rawData = cherrypy.request.body.read(int(cherrypy.request.headers['Content-Length']))
        b = json.loads(rawData)
# do something with b, in this case I am returning it inside another object
        return json.dumps({'x': 4, 'c': b})

def CORS():
    cherrypy.response.headers["Access-Control-Allow-Origin"] = "http://localhost"

if __name__ == '__main__':
    conf = {
        '/': {
            'request.dispatch': cherrypy.dispatch.MethodDispatcher(),
            'tools.CORS.on': True,
        }
    }
    cherrypy.tools.CORS = cherrypy.Tool('before_handler', CORS)
    cherrypy.quickstart(DataView(), '/d/', conf)

Save this as cherryserver.py and start it in the normal way (i.e. python cherryserver.py). Note that, for testing, my JavaScript is on localhost, so the CORS method contains a header explicitly allowing this origin. The Quickstart call mounts the class DataView to the URL /d/.

A basic client

Below is a very basic web page that makes a POST request to our server containing some JSON and then displays the returned JSON:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8"></meta>

  <script>
    var HttpClient = function() {

      this.post = function(url, data, callback) {
        var httpRequest = new XMLHttpRequest();
        httpRequest.open("POST", url, true);
        httpRequest.onreadystatechange = function() {
          if (httpRequest.readyState == 4 && httpRequest.status == 200)
            callback(httpRequest.responseText);
        };
        httpRequest.send(JSON.stringify(data));
      };
    };

    var req = new HttpClient();
    var rURL = 'http://localhost:8080/d/';
    req.post(rURL, {"a": 1, "delta": "data"}, function(response) {
      document.getElementById('main').innerHTML = response;
    });

</script>
</head>
<body>
<div>Hello world</div>
<div id='main'></div>
</body>

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s