If you've done any back end web development in Python, you've probably come across WSGI at some point. If you're just getting started, the terms and technologies surrounding WSGI can be a bit confusing. In this post, I'm going to explain the major players in this space and how they work together.
The Before Times
Back in the day, when you wanted to write a Python web application you had to use one of a few technologies available such as CGI and mod_python. These options tended to be limiting and had performance and security problems. The python community wanted more options for writing web apps while consolidating the various architectures in place.
WSGI (pronounced wiz-gee) stands for Web Server Gateway Interface and it's a spec for a software interface between a web server and a python application. The point of WSGI is to allow any web server to work with any Python application as long as both sides implement the spec. You can see the spec here in PEP 333, but basically it boils down to the concept of the python app making a callable object (e.g. a function) available to the web server. When the web server receives a request from the client that should be processed by the python app, it calls this function. The python app runs and returns the result to the web server, and the server passes it on to the client.
Here is an example of a basic python app that implements the WSGI spec:
Here, the function application is the callable object I referred to above. This is the function that the web server will call when it wants the python app to process a request. It takes two parameters:
environ - a dictionary that contains information about the request and various settings from the WSGI server that made the call.
start_response - a function that must be called by the python application to start the HTTP response. If the python app does not call this method, the request will not be properly processed by the server.
Also notice that the return value of the application function is the actual response body. Returning a value is optional. Of course, not all HTTP responses have bodies (e.g. HTTP status code 204).
And that's basically it. As long as the Python app provides this callable and the web server is capable of invoking it and passing in the correct arguments, any combination of web server and Python app can work together.
If you'd like to actually see a WSGI app run, it's easy to do. First you'll need a WSGI compliant server. I recommend uWSGI, which has a simple command line interface. It can be installed by running
Save the python script I listed earlier into a file called app.py. Run the uWSGI server by typing this on the command line:
and browsing to http://localhost:8080
Notice that the python app has no import statements. There are no external libraries or frameworks used. It's as plain a python app as they come. The magic is all in the implementation of the WSGI spec. It's important to note that if you don't name the function "application" it won't work. That's the default name that the uWSGI server expects, but it can be configured to work with a different name if you like.
How it all fits together
The confusing part about WSGI is that there is a lot of history here, a lot of options, and the documentation, while not bad, isn't always that clear. Since both Flask and uWSGI are popular options in this realm, I'm going to focus on them and clear up some confusing aspects of how they work.
You may have heard of this framework in passing or seen references to it in your Flask application. Werkzeug (pronounced work-zoig or vairk-zoig if you want to get technical), is a library written by Armin Ronacher that consists of a large set of utilities designed to make writing WSGI compliant Python applications easier.
Flask is a popular framework for writing WSGI complient web applications in Python. It was also written by Armin Ronacher and is implemented using the Werkzeug library. You might have noticed that Flask comes with its own development level server. Well, this is actually Werkzeug's dev server being exposed through Flask.
uWSGI is a popular web server that implements the WSGI standard. Don't get confused by the name. WSGI is a specification, uWSGI is a web server. That little "u" in the front makes a big difference. It's pretty common to pair Flask and uWSGI since they both talk WSGI. The uWSGI server is a full featured HTTP server that is quite capable of running production web apps. However, it's not as performant as nginx at serving static content, so it's pretty common to see nginx sitting in front a uWSGI server.
Here's where some poor naming choices make things even more confusing. So we know WSGI is a software spec, uWSGI is a server, so what the hell is uwsgi? When it's spelled using all lowercase letters, it refers to a binary protocol for connecting the uWSGI server to other applications. As you no doubt recall from the above paragraph, it's common for uWSGI to be used in conjunction with nginx. Well, the uwsgi protocol is how the two web servers talk to each other.
Here is the basic flow of data from the client through the python app:
So there you go, a brief and hopefully useful introduction into the world of WSGI.