Skip to the content.

Building Your First WSGI Application

Now that we understand the basics of web servers and WSGI, let’s build our first WSGI application. This section will guide you through creating a simple WSGI application from scratch.

Step 1: Set Up Your Environment

First, make sure you have Python and pip installed on your system (I hope you’re using linux). If not, you can download and install them from the official Python website.

Create a new directory for your project and navigate into it:

mkdir my_wsgi_app
cd my_wsgi_app

Step 2: Create Your WSGI Application

Create a new file called app.py and open it in your favorite text editor. Add the following code:

#app.py

def simple_app(environ, start_response):
    status = '200 OK'
    headers = [('Content-type', 'text/plain; charset=utf-8')]
    start_response(status, headers)
    return [b"Hello, World!"]

if __name__ == "__main__":
    from wsgiref.simple_server import make_server
    server = make_server('localhost', 8000, simple_app)
    print("Serving on http://localhost:8000")
    server.serve_forever()

This code defines a basic WSGI application called simple_app that responds with “Hello, World!” and sets up a simple server to run the application.

Step 3: Run Your Application

python app.py

You should see the message “Serving on http://localhost:8000”. Open your web browser and navigate to http://localhost:8000. You should see “Hello, World!” displayed on the page.

Step 4: Understanding the Code

Let’s break down the code in app.py:

The WSGI Application:

def simple_app(environ: dict, start_response):
    status = '200 OK'
    headers = [('Content-type', 'text/plain; charset=utf-8')]
    start_response(status, headers)
    return [b"Hello, World!"]

According to PEP 3333, the web application must be a callable (a function, method, class, or instance with a call method) that accepts two arguments:

These arguments will be injected by the WSGI server when it calls the simple_app function.

It’s important to note that start_response MUST be called. Otherwise, the headers and status code of the response will not be set, and you’ll receive an error.

If you’re curious, you can look at the internal function start_response that is injected by the built-in module wsgiref. In the image below, you can see that start_response mainly:

Image the start_response function

Setting Up the Server

if __name__ == "__main__":
    from wsgiref.simple_server import make_server
    server = make_server('localhost', 8000, simple_app)
    print("Serving on http://localhost:8000")
    server.serve_forever()

Notice that make_server receives the function simple_app as an argument. This is where we tell the WSGI server to execute this function when it receives a call from a client.

Step 5: Adding More Features

You can extend your WSGI application by adding more features, such as handling different URL paths or serving HTML templates. Here’s an example of handling different paths:

def simple_app(environ, start_response):
    path = environ.get('PATH_INFO', '/')
    if path == '/':
        response_body = b"Hello, World!"
    elif path == '/goodbye':
        response_body = b"Goodbye, World!"
    else:
        response_body = b"Not Found"
        status = '404 Not Found'
        headers = [('Content-type', 'text/plain; charset=utf-8')]
        start_response(status, headers)
        return [response_body]

    status = '200 OK'
    headers = [('Content-type', 'text/plain; charset=utf-8')]
    start_response(status, headers)
    return [response_body]

With this code, navigating to http://localhost:8000/goodbye will display “Goodbye, World!”, and any other path will display “Not Found” with a 404 status.

Next Step:

Exploring WSGI Middleware