Thursday, September 17, 2009

Twisted Web in 60 seconds: generate a page dynamically


Welcome to the second installment of "Twisted Web in 60 seconds". The goal of this installment is to show you how to dynamically generate the contents of a page using APIs from Twisted Web. If you missed the first installment on serving static content, you may want to take a look at that first. Ready? Let's begin.




Taking care of some of the necessary imports first, we'll import Site and the reactor:


from twisted.internet import reactor
from twisted.web.server import Site


The Site is a factory which associates a listening port with the HTTP protocol implementation. The reactor is the main loop that drives any Twisted application, we'll use it to actually create the listening port in a moment.




Next, we'll import one more thing from Twisted Web, Resource. An instance of Resource (or a subclass) represents a page (technically, the entity addressed by a URI).


from twisted.web.resource import Resource




Since I'm going to make the demo resource a clock, we'll also import the time module:


import time




With imports taken care of, the next step is to define a Resource subclass which has the dynamic rendering behavior we want. Here's a resource which generates a page giving the time:


class ClockPage(Resource):
isLeaf = True
def render_GET(self, request):
return "<html><body>%s</body></html>" % (time.ctime(),)




Setting isLeaf to True indicates that ClockPage resources will never have any children.




The render_GET method here will be called whenever the URI we hook this resource up to is requested with the GET method. The byte string it returns is what will be sent to the browser.




With the resource defined, we can create a Site from it:


resource = ClockPage()
factory = Site(resource)


Just as with the previous static content example, this configuration puts our resource at the very top of the URI hierarchy, ie at /.

And with that Site instance, we can tell the reactor to create a TCP server1 and start servicing requests:

reactor.listenTCP(8880, factory)
reactor.run()




Here's the code with no interruptions:


from twisted.internet import reactor
from twisted.web.server import Site
from twisted.web.resource import Resource
import time

class ClockPage(Resource):
isLeaf = True
def render_GET(self, request):
return "<html><body>%s</body></html>" % (time.ctime(),)

resource = ClockPage()
factory = Site(resource)
reactor.listenTCP(8880, factory)
reactor.run()



Tune in next time to learn about how to put different resources at different URIs.

1 comment:

  1. Dude, these posts are super useful. The Twisted documentation is hard to understand for someone coming from other web frameworks. This has become part of the de facto documentation for me.

    Thank you so much.

    ReplyDelete