The Web Server Gateway Interface
Start course

This course is the second course in two-part series on how to build an application in Python. In the first course, we built a data ingestion process that extracted named entities from articles across a few different publications. We extracted named entities from around 100,000 articles and we saved the results into Cloud Firestore. In this second course, we'll explore the codebase for a web application used to visualize those results.

We'll kick off the course by checking out some quality of life changes implemented while developing this app. That includes a custom bash theme, a replacement debugger, a debugger command for starting an IPython shell, and pytest plugins. After that, we're going to review the data access layer and its accompanying tests. That's going to include multiple implementations of each data access service. Then we'll check out Python's web application standard.

Next, we'll review the web application layer and its accompanying tests. That's going to include a fast web application framework, custom middleware, request hooks, and application configuration. After that, we're going to review the presentation layer, including a Vue.js app and materialize CSS. Finally, we're going to run the app locally and trace some requests through the application using the debugger.

If you have any feedback relating to this course, feel free to contact us at≥

Learning Objectives

  • Implement a few developer quality of life changes 
  • Implement a testable data access layer 
  • Understand how a Python web app operates 
  • Understand how to build and test a more complex web app
  • Understand how to use ipdb and IPython
  • Enhance your knowledge of the Python programming language

Intended Audience

This course is intended for software developers or anyone who wants to learn more about building apps with Python.


  • Before taking this course, please make sure you have taken the first course in this two-part series: Building a Python Application: Course One
  • You should also have an understanding of Python 3, Linux CLI, HTML/JS, and Git


The source code for the course is available on GitHub.


Hello and welcome. The Python web application standard, is the Web Server Gateway Interface. Often abbreviated as WSGI, and I pronounce it as wizgee, though I've also heard it pronounced Whiskey, as in the alcoholic beverage.

The WSGI standard goes back to 2003, with an update in 2010 for Python 3. The specification defines how WSGI applications and WSGI servers should communicate. Separating the server from the application has several advantages.

First, we can reuse the same server code for multiple applications. Second, as long as the application follows the WSGI specifications, we can make changes to the app, without having to make changes to our server. We're going to be using Gunicorn for our WSGI server. The job of the server is to accept requests, and hand off the request info to our application. Let's review what the hand off looks like.

A WSGI application needs to be a callable that accepts two positional arguments. The first is a dictionary containing environment details, and the second is a function reference. We run the application server by specifying the location of our callable WSGI application.

Notice here we have a single function. We specify the application by passing in the package, module, and callable, and setting the time out here, it's allow us to debug without Gunicorn, restarting the application. This is going to expose the application on port 8000.

Running it, we can see that this message is returned here. So nothing too fancy, just basically what we expect. Let's run it again though. And we're going to first set a breakpoint, and configure ipdb as our debugger. 

Okay, with this running, let's reload the browser, and this is going to block, because we are now in the debugging session. Here's where the current breakpoint is located. And notice this nice syntax highlighting. By typing a question mark, we can see the available ipdb commands.

Let's review the arguments passed to our app. Here's our environment dictionary. Not the most readable. Though, we can use pretty-printing to format this just a bit better. The WSGI specification defines a set of required CGI environment variables, that includes these values here. And the spec also includes a set of required WSGI variables.

Let's check out the second argument which is a function. Using psource we can inspect the source for this start_response function. This is provided by the WSGI server. Recall that we created an alias called interacti, that is going to start up an IPython terminal. So let's test that out now.

Calling environ here, is going to automatically pretty-print the result of that dictionary. Notice, now we get pretty-printing by default. Let's exit the IPython shell, by detaching using Control + D. This is going to close out of the IPython's terminal and bring us back to the debugger. We're currently on line eight, though, it's not been called yet. Typing n will move to the next line. And we can inspect the status by typing the name, and by typing n. It's going to move us forward again.

Hitting enter, will just rerun the last command. And notice we're now on line 11, which is the return. The line that we're on hasn't been run. So if we check the return value now, notice it doesn't exist. Moving to the next line, that's gonna actually return the text, which we can inspect with retval, and we see our text. Okay, let's close out of this.

WSGI applications are conceptually simple. They're just a callable that accepts two positional arguments. The first is a dictionary with WSGI and environment variables. The second is a callable, that's used to start the HTTP response. And these values are provided by the server.

There are a lot of different WSGI application frameworks, that take different approaches to building Python web apps. However, at their core, they all share this same basic structure. The WSGI server expects a callable accepting two server provided arguments.

Anything built on top of that, is what separates out the different application frameworks. Some of the popular frameworks include Flask and Django. Flask is a micro web application framework. It's an un-opinionated framework, which makes it easy to map a URL path to a function. Django is on the other side of the spectrum. Django is an opinionated framework, which follows a Model-View-Controller pattern. It also includes a lot of the common components required for building web applications.

The WSGI specification has existed for years. So there is a lot of frameworks out there, that range from ultra minimalist to fully loaded. We're going to use a framework called Falcon. Falcon is on the more minimal side. It's fast, it's well unit tested and well documented. And we'll check it out more in another lesson.

For now, that's going to wrap up this lesson. In our next lesson, we're going to explore the web application layer. So, whenever you're ready, I will see you in the next lesson.


Course Introduction - Quality of Life for Developers - What Is It That We're Building? - Exploring the Data Access Layer - Exploring the Web Application Layer - Exploring the Front End Code - Running the Web App - Summary / Next Steps

About the Author
Learning Paths

Ben Lambert is a software engineer and was previously the lead author for DevOps and Microsoft Azure training content at Cloud Academy. His courses and learning paths covered Cloud Ecosystem technologies such as DC/OS, configuration management tools, and containers. As a software engineer, Ben’s experience includes building highly available web and mobile apps. When he’s not building software, he’s hiking, camping, or creating video games.