ajax fun with jquery & python

the other day i tried to come up with a minimalistic Ajax setup — minimalistic in the sense of minimal coding overhead. my ingredients of choice were jquery and JavaScript on the client side and python on the server side. the goal was to use both GET and POST REST calls for obtaining the dynamic data and utilize JSON as the data format.

the python server code makes use of python’s BaseHTTPServer.HTTPServer and BaseHTTPServer.BaseHTTPRequestHandler classes:

AjaxServer extends BaseHTTPServer.HTTPServer and supplies Handler which in turn extends BaseHTTPServer.BaseHTTPRequestHandler. the Handler class also implements the GET and POST REST interfaces.

the server supports

  • text/html GETs on file names from the document root, retrieving index.html for GETs on directories, and
  • application/json GETs on
  • /ajax/time returning the current time
  • /ajax/processcount returning the number of currently running processes
  • application/json POSTs on any URL returning the length of the posted content

the client is a simple HTML5 page that uses jquery’s ajax() support to invoke the GET REST and POST REST calls on our python server.

client code

<!DOCTYPE html>
<html lang=”en”>
    <meta charset=”utf-8”>
    <title>AJAX sandbox</title>
    <meta name=”viewport” content=”width=device-width, initial-scale=1.0”>
    <meta name=”description” content=”not found document”>
    <meta name=”author” content=”hud@zurich.ibm.com”>
    <link href=”css/bootstrap.css” rel=”stylesheet”>
      body {
      padding-top: 60px; / 60px to make the container go all the way to the bottom of the topbar /

<!– Le HTML5 shim, for IE6-8 support of HTML5 elements –>     <!–[if lt IE 9]>         <script src=”http://html5shim.googlecode.com/svn/trunk/html5.js”></script>         <![endif]–>   </head>   <body id=”home”>     <div>OK, let’s go!</div>

<div>current time: <span id=”ajax-datetime”>waiting for time update…</span></div>

<div>current process count: <span id=”ajax-processcount”>waiting for process count update…</span></div>

<div><input id=”typehere” type=”text” value=”type here” /></div>     <div id=”ajax-processedinput”>waiting for result</div>

<!– JavaScript at the bottom to speed up page loading –>     <script src=”/js/jquery-1.7.2.min.js”></script>     <script src=”/js/bootstrap.min.js”></script>     <script src=”/js/ajax-datetime.js”></script>     <script src=”/js/ajax-processcount.js”></script>     <script src=”/js/ajax-processinput.js”></script>   </body> </html>

the HTML5 code itself doesn’t really do anything. the magic happens in the ajax-datetime.js, ajax-processcount.js, ajax-processinput.js javascripts:

ajax-datetime.js calls the /ajax/time GET REST method every 3 seconds and sets the content of the #ajax-datetime div element to the return value of the GET REST call:

$(document).ready(function() { 
    function updateDateTime() {
            cache: false,
            url: “/ajax/time”,
            type: “GET”,
            contentType: “application/json”
        }).done(function(json) {

setInterval(updateDateTime, (3 * 1000));


pretty much the same procedure is used for ajax-processcount.js:
$(document).ready(function() { 

function updateProcessCount() {
        cache: false,
        url: "/ajax/processcount",
        type: "GET",
        contentType: "application/json"
    }).done(function(json) {
    }).error(function(json) {
        $("#ajax-processcount").html("connection to server lost...");

setInterval(updateProcessCount, (5 * 1000));


the only difference is that ajax-processcount.js invokes the /ajax/processcount GET REST method and does so every 5 seconds — demonstrating the asynchronous nature of AJAX rather nicely.

while the previous two javascripts used GET to retrieve information from our python server, the next, ajax-processinput.js attaches itself to the #typehere text input field and POSTs the content of the field to /ajax/processinput, returning the result of the POST REST call via the #ajax-processedinput div element:

$(document).ready(function() { 

function processInput() {
        cache: false,
        url: "/ajax/processinput",
        type: "POST",
        contentType: "application/json",
        dataType: "json",
        data: JSON.stringify({ "input": $("#typehere").val() })
    }).done(function(json) {
    }).error(function(json) {
        $("#ajax-processedinput").html("connection to server lost...");

$("#typehere").change(function () {


unfortunately, even though i tell ajax(...) that i’m sending JSON — the contentType: "application/json" line — jquery will not convert the data i’m sending into JSON and i need to explicitly turn it into JSON myself:
data: JSON.stringify({ “input”: $(“#typehere”).val() })

server code

the server code consists of two modules: ajaxserver and handler.

handler contains the Handler class which extends BaseHTTPServer.BaseHTTPRequestHandler and implements the GET and POST REST calls explained earlier:

!/usr/bin/env python2.6

-- encoding: utf-8 --

’‘’ handler.Handler is the HTTP handler for ajaxserver ‘’‘

import BaseHTTPServer import logging as log import os import subprocess

try: import simplejson as json except ImportError: import json

from datetime import datetime

class Handler(BaseHTTPServer.BaseHTTPRequestHandler):

def logRequest(s):
    log.debug("%s: %s/%s" %(s.client_address, s.command, s.path))

def do_GET(self):

    path = self.path

    if 'Content-type' in self.headers:
        contentType = self.headers['Content-type']
        contentType = 'text/html'

    log.debug("ajaxserver.GET: Path %s" % path)
    log.debug("ajaxserver.GET: Content-type %s" % contentType)

    if contentType.startswith('text/html'):
        (respCode, respContent, respContentType) = self.do_GET_HTML()
    elif contentType.startswith('application/json'):
        (respCode, respContent, respContentType) = self.do_GET_JSON()

    self.send_response(respCode, "thank you")
    self.send_header('Content-type', respContentType)
    self.send_header('Content-length', len(respContent))


def do_POST(self):

    path = self.path
    contentType = self.headers['Content-type']

    log.debug("ajaxserver.POST: Path %s" % path)
    log.debug("ajaxserver.POST: Content-type %s" % contentType)

    if not contentType.startswith('application/json'):
        self.send_response(404, "oh, shiny!")
        self.send_header('Content-type', 'application/json')
        self.wfile.write(json.dumps({ "error": "only accepting application/json" }))

    contentLength = int(self.headers['Content-length'])
    content = self.rfile.read(contentLength)

    log.debug("ajaxserver.POST: Content-length %d" % contentLength)
    log.debug("ajaxserver.POST: Content: %s" % content)

    data = json.loads(content)
    if 'input' not in data:
        log.debug("ajaxserver.POST: missing input parameter: %s" % content)
        self.send_response(404, "oh, shiny!")
        self.send_header('Content-type', 'application/json')
        self.wfile.write(json.dumps({ "error": "missing input parameter" }))

    self.send_response(200, "oh, shiny!")
    self.send_header('Content-type', 'application/json')
    self.wfile.write(json.dumps({ "processed": len(data['input'])}))


def do_GET_HTML(self):

    docRoot = self.server.docRoot
    docPath = "%s%s" % (docRoot, self.path)
    errorPath = "%s/not-found.html" % docRoot

    if self.path.startswith('../'):
        log.debug('ajaxserver.GET(HTML): "%s" trying to escape from the sandbox' % self.path)
        docFile = open(errorPath, 'r')
        code = 404
    elif docPath.endswith('/') and os.path.exists("%sindex.html" % docPath):
        log.debug('ajaxserver.GET(HTML): serving %sindex.html for %s' % (docPath, self.path))
        docFile = open("%sindex.html" % docPath, 'r')
        code = 200
    elif os.path.exists(docPath):
        log.debug('ajaxserver.GET(HTML): serving %s for %s' % (docPath, self.path))
        docFile = open(docPath, 'r')
        code = 200
        log.debug('ajaxserver.GET(HTML): no document found for %s' % self.path)
        docFile = open(errorPath, 'r')
        code = 404

    doc = docFile.read()

    return (code, doc, 'text/html')

def utilProcessCount(self):
    psCmd = subprocess.Popen(["ps", "ax"], stdout=subprocess.PIPE)
    wcCmd = subprocess.Popen(["wc", "-l"], stdin=psCmd.stdout, stdout=subprocess.PIPE)
    count = wcCmd.communicate()[0]

    return json.dumps({ 'processcount': int(count) - 1 })

def do_GET_JSON(self):

    if self.path.startswith('/ajax/time'):
        return (200, '{ "time": "%s" }' % datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S UTC'), 'application/json')

    if self.path.startswith('/ajax/processcount'):
        return (200, self.utilProcessCount(), 'application/json')

    return (200, '{ "resp": "bark!" }', 'application/json')

ajaxserver contains the AjaxServer class which extends the BaseHTTPServer.HTTPServer class and is the driver of my simple python web server. it also contains the setup code to instantiate the server and start it:

!/usr/bin/env python2.6

-- encoding: utf-8 --

’‘’ ajaxServer is a simple proof-of-concept web server for serving AJAX pages and their contents. ‘’‘

import BaseHTTPServer import logging as log import logging.handlers import os import re import subprocess import sys import urllib2

import handler

from datetime import date

class AjaxServer(BaseHTTPServer.HTTPServer):

def __init__(self, serverAddress, requestHandlerClass, docRoot):
    BaseHTTPServer.HTTPServer.__init__(self, serverAddress, requestHandlerClass)
    self.docRoot = docRoot

from python module doc

def run(server_class=BaseHTTPServer.HTTPServer, handler_class=BaseHTTPServer.BaseHTTPRequestHandler, root=’root’, ip=’‘, port=8000):

server_address = (ip, port)

httpd = server_class(server_address, handler_class, root)
log.info("ajaxserver: waiting for requests")

if name == ‘main’:

log.basicConfig(level = log.DEBUG,
format = '%(asctime)s %(levelname)-8s %(message)s',
datefmt = '%a, %d %b %Y %H:%M:%S')

ip = ''
port = 8000
docRoot = '../root'


# start the server
log.info("ajaxserver: starting HTTP server on %s:%d" %(ip, port))
run(server_class=AjaxServer, handler_class=handler.Handler, ip=ip, port=port, root=docRoot)
log.info("ajaxserver: terminating")

except KeyboardInterrupt, k: print “\r>>terminated by user, good bye!>>” log.info(“aborted by user, terminating”)

running it

start the ajax server:

./ajaxserver Sun, 01 Jul 2012 16:35:12 INFO ajaxserver: starting HTTP server on Sun, 01 Jul 2012 16:35:12 INFO ajaxserver: waiting for requests

then point your browser to http://localhost:8000/ — in your terminal running ajaxserver you’ll see a bunch of log lines showing you the requests triggered by loading the index.html page.

the browser will initially show just the static text of index.html

— after a couple of seconds the current date and time will be displayed and continuously updated, followed by the current process count of your machine. when you enter text into the text input field and tab out, the length of your input will be shown next to it.

all three activities are happening independently from one another, the page itself is never reloaded (as you can verify in the ajaxserver log output).