Hello WSGI

A WSGI application is just a callable object the responds to requests by taking two arguments. The first one is the WSGI environment and the second is the start_response. The environment is a Python dictionary containing information about the CGI environment. start_response is a callback which takes two inputs the response status and headers. The status is a string representation like 200 OK or any other HTTP status code followed by a word. headers is a list of two values tuples or possible HTTP headers. The return value of start response is another callable which when invoked return the body of the response.

It is the responsibility of the WSGI server to implement this callback. That is, the Python web application or the framework simply receive it.

The WSGI application is invoked with the environment and start_response, it may or may not use information from the environment, when done it should return an iterable yielding zero or more strings which then become the body of the response. It may also manipulate the headers passed on to start_response before invoking it.

The following is a complete valid WSGI application:

def hello_world_app(environ, start_response):
    status = '200 OK'  # HTTP Status
    # HTTP Headers
    headers = [('Content-type', 'text/plain; charset=utf-8')]
    start_response(status, headers)

    # The returned object is going to be printed
    return [b"Hello World"]

Running a WSGI application

To actually make use of the above example, you need to invoke it with a valid WSGI server. Luckily, we don’t need to fully setup a HTTP server, because the Python standard library already has already a simple HTTP server which implements the WSGI protocol which we can use to test our app. To make use of it you can do:

from wsgiref.simple_server import make_server

def hello_world_app(environ, start_response):
    status = '200 OK'  # HTTP Status
    # HTTP Headers
    headers = [('Content-type', 'text/plain; charset=utf-8')]
    start_response(status, headers)

    # The returned object is going to be printed
    return [b"Hello World"]

httpd = make_server('', 8000, app)
print("Serving on port 8000...")
# Serve until process is killed
httpd.serve_forever()

Note

In reality, a WSGI server is usually deployed behind a full blown HTTP server, which serves as a reverse proxy for the WSGI server. That is, the HTTP server (for example NGinx) listen to HTTP or HTTPS requests on port 80 or 443 and then redirects them to the appropriate socket to which the WSGI server is bound to.

Exercise 1

Write your own callable class which is a valid WSGI application.

Solution

class HelloWSGI:

     def __call__(self, environ, start_response):
         self.start_response('200 OK', [('Content-Type', 'text/plain')])
         yield b"Hello World!\n"