XML.com: XML From the Inside Out
oreilly.comSafari Bookshelf.Conferences.

advertisement

Introducing WSGI: Python's Secret Web Weapon, Part Two

October 04, 2006

Web Server Gateway Interface Part II: Making Use of Middleware

In Part I we discussed how the Web Server Gateway Interface (WSGI) is helping to unify the Python web-framework world by providing a standard API through which different web applications can operate with different servers. We also looked at the HTTP protocol and how to write and deploy WSGI applications. In the second part of this article, we'll look at how to make use of existing middleware components to add functionality to your WSGI applications.

What is Middleware?

WSGI middleware is software that behaves like a server to an application, passing an environ dictionary and start_response callable to the application in the same way a server would. Middleware components also expect the application to return an iterable, such as a list of strings, or to be iterable themselves. Importantly, middleware also behaves like an application to the server, expecting to receive an environ dictionary and start_response callable itself, and returning an iterable back to the server.

Middleware effectively sits between a server and an application, isolating one from the other, and can therefore do any of the following or a combination thereof:

  • Provide more functionality by adding a key to the environ dictionary
  • Change the status
  • Intercept an error
  • Add, remove, or change headers
  • Change a response

Middleware is therefore extremely powerful and can build a broad range of discrete components that can be used with different WSGI servers and applications. For example, a middleware component can:

  • Produce error documents when certain status codes are received (typically responding to 404 and 500 codes)
  • Email error reports to a developer if a problem occurs
  • Provide interactive debugging facilities
  • Forward requests to other parts of the application
  • Test the API compliance of applications and servers to the WSGI
  • Authenticate a user
  • Cache pages
  • Provide a session store
  • Gzip the response

Have a look at the middleware and utilities page on the wsgi.org site to get an idea of some of the middleware that already exists. Paste, one of the packages mentioned, contains many middleware components of its own that are not listed separately on the wsgi.org page, but are worth taking the time to investigate.

Getting Started

As an example, we'll create an application that uses session middleware to store the value of a variable between requests. Here is the application that needs session support:

    def application(environ, start_response):
        session = environ['beaker.session']
        if not session.has_key('value'):
            session['value'] = 0
        session['value'] += 1
        session.save()
        start_response('200 OK', [('Content-type', 'text/plain')])
        return ['The current value is: %d' % session['value']]

The application stores a variable called value in the session store. On each request, the variable is incremented and a message stating its current value is returned. For this application to work, the environ dictionary needs to contain the beaker.session key, which is provided by the session middleware from the beaker package.

Here's how you would wrap the application in beaker's session middleware:

    from beaker.session import SessionMiddleware

    application = SessionMiddleware(
        application,
        key='mysession',
        secret='randomsecret',
    )

The new application object behaves just like a normal WSGI application. When the combined application and middleware object is called, the SessionMiddleware adds the beaker.session key to the environ dictionary and calls the original application with the modified environ dictionary and start_response() callable. The application then calls start_response() as normal and returns an iterable to the middleware. The middleware returns this information to the server so that, from the server's point of view, the combined middleware and application can be treated in exactly the same way as a normal WSGI application.

You can test the example above by serving the finished application with the following code and visiting http://localhost:8000 on your local machine once the server is running:

    def application(environ, start_response):
        session = environ['beaker.session']
        if not session.has_key('value'):
            session['value'] = 0
        session['value'] += 1
        session.save()
        start_response('200 OK', [('Content-type', 'text/plain')])
        return ['The current value is: %d' % session['value']]
        
    from beaker.session import SessionMiddleware

    application = SessionMiddleware(
        application,
        key='mysession',
        secret='randomsecret',
    )
    
    from wsgiref import simple_server
    httpd = simple_server.WSGIServer(
        ('',8000),
        simple_server.WSGIRequestHandler,
    )
    httpd.set_app(application)
    httpd.serve_forever()

If you are running a version of Python prior to 2.5, you will need to download and install the wsgiref package as described in the Part I of this article. You will also need to download and install the beaker package, which provides SessionMiddleware.

If you test the example above, you may find the count goes from 1 to 3, missing 2. This is because many web browsers try to retrieve a /favicon.ico file the first time a site is visited, and this request also results in value being incremented. If you have the LiveHTTPHeaders extension for the Firefox web browser installed, you'll be able to see the request being made when you visit a site not already in the browser's cache.

Pages: 1, 2, 3

Next Pagearrow