This is an example of a simple asynchronous Python web server using Twisted. This is a copy of Jp Calderone's Twisted Web in 60 seconds: handling POSTs example modified to accept a JSON payload in the POST request instead of form data. It also uses his Simple Python Web Server example to run the web server as a daemon with twistd.
webserver.py
"""
http://jcalderone.livejournal.com/49707.html
http://labs.twistedmatrix.com/2008/02/simple-python-web-server.html
usage:
$ twistd -y webserver.py
"""
from pprint import pprint
from twisted.application.internet import TCPServer
from twisted.application.service import Application
from twisted.web.resource import Resource
from twisted.web.server import Site
class FormPage(Resource):
def render_GET(self, request):
return ''
def render_POST(self, request):
pprint(request.__dict__)
newdata = request.content.getvalue()
print newdata
return ''
root = Resource()
root.putChild("form", FormPage())
application = Application("My Web Service")
TCPServer(8880, Site(root)).setServiceParent(application)
test_post.py
Here is a simple test client using httplib2 to send a POST request with some JSON data. I used Mark Pilgrim's Dive Into Python 3 Section 14.6 as a reference.
import httplib2
from datetime import datetime
import simplejson
TESTDATA = {'woggle': {'version': 1234,
'updated': str(datetime.now()),
}}
URL = 'http://localhost:8880/form'
jsondata = simplejson.dumps(TESTDATA)
h = httplib2.Http()
resp, content = h.request(URL,
'POST',
jsondata,
headers={'Content-Type': 'application/json'})
print resp
print content
Run the web server
$ twisted -y webserver.py
Run the test POST
twistd.log
Here are the results stored in twistd.log
.
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] {'_adapterCache': {},
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'args': {},
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'channel': <twisted.web.http.HTTPChannel instance at 0x7fb409dc8248>,
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'client': <twisted.internet.address.IPv4Address object at 0x1b48f50>,
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'clientproto': 'HTTP/1.1',
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'content': <cStringIO.StringO object at 0x1b4c068>,
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'cookies': [],
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'headers': {'date': 'Thu, 26 Aug 2010 03:02:37 GMT', 'content-type': 'text/html', 'server': 'TwistedWeb/10.0.0'},
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'host': <twisted.internet.address.IPv4Address object at 0x1b48fd0>,
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'method': 'POST',
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'notifications': [],
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'path': '/form',
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'postpath': [],
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'prepath': ['form'],
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'queued': 0,
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'received_cookies': {},
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'received_headers': {'host': 'localhost:8880', 'content-type': 'application/json', 'accept-encoding': 'identity', 'content-length': '70', 'user-agent': 'Python-httplib2/$Rev$'},
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'requestHeaders': Headers({'host': ['localhost:8880'], 'content-type': ['application/json'], 'accept-encoding': ['identity'], 'content-length': ['70'], 'user-agent': ['Python-httplib2/$Rev$']}),
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'responseHeaders': Headers({'date': ['Thu, 26 Aug 2010 03:02:37 GMT'], 'content-type': ['text/html'], 'server': ['TwistedWeb/10.0.0']}),
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'site': <twisted.web.server.Site instance at 0x1b419e0>,
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'sitepath': [],
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'stack': [],
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'transport': <HTTPChannel #1 on 8880>,
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 'uri': '/form'}
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] {"woggle": {"updated": "2010-08-25 20:02:37.449333", "version": 1234}}
2010-08-25 20:02:37-0700 [HTTPChannel,1,127.0.0.1] 127.0.0.1 - - [26/Aug/2010:03:02:36 +0000] "POST /form HTTP/1.1" 200 - "-" "Python-httplib2/$Rev$"