Why WSGI?

Back in the day, Python web frameworks were typically written against CGI, FastCGI, mod_python, or some other custom API of a specific web server. WSGI was thus created as an implementation-agnostic interface between web servers and web applications or frameworks to promote common ground for portable web application development.


Python currently boasts a wide variety of web application frameworks. This wide variety of choices can be a problem for new Python users, because generally speaking, their choice of web framework will limit their choice of usable web servers, and vice versa.[1]

What is WSGI

Web Server Gateway Interface is a means of plugging a Python web application with a web server. It acts as a bridge between the two.

WSGI is an API (of sorts)

WSGI is not a server, a python module, a framework nor an implementation, it is a specification. It is an interface specification by which server and application communicate.

Specification

The WSGI interface has two sides: the “server” or “gateway” side, and the “application” or “framework” side. The server side invokes a callable object that is provided by the application side. The specifics of how that object is provided are up to the server or gateway. It is assumed that some servers or gateways will require an application’s deployer to write a short script to create an instance of the server or gateway, and supply it with the application object. Other servers and gateways may use configuration files or other mechanisms to specify where an application object should be imported from, or otherwise obtained.[1]

Clarification on Terms

Before going further, we should address some confusing terminology when talking about WSGI. These three separate terms that appear interchangeable, but actually have distinct meanings[2]:

WSGI

WSGI: A Python spec that defines a standard interface for communication between an application or framework and an application/web server. This was created in order to simplify and standardize communication between these components for consistency and interchangeability. This basically defines an API interface that can be used over other protocols.

uWSGI

uWSGI: An application server container that aims to provide a full stack for developing and deploying web applications and services. The main component is an application server that can handle apps of different languages. It communicates with the application using the methods defined by the WSGI spec, and with other web servers over a variety of other protocols. This is the piece that translates requests from a conventional web server into a format that the application can process.

uwsgi

uwsgi: A fast, binary protocol implemented by the uWSGI server to communicate with a more full-featured web server. This is a wire protocol, not a transport protocol. It is the preferred way to speak to web servers that are proxying requests to uWSGI.

Application Programming

Three common building blocks when deploying a Python web application to production are:

  • • A web server (like nginx)
  • • A WSGI application server (like Gunicorn)
  • • Your actual application (written in framework like Django or Flask)

The web server accepts requests, takes care of general domain logic and takes care of handling https connections. Only requests which are meant to arrive at the application are passed on toward the application server and the application itself. The application code does not care about anything except being able to process single requests.


The application server is what we’re talking about here. Let’s look into what it does.

The Application Side

The application side of the WSGI is a simple object that accepts two arguments and can be called from code. This example shows a simple WSGI application that returns a static “Hello world!” page:

def simple_app(environ, start_response):
    status = '200 OK'
    response_headers = [('Content-type','text/plain')]
    start_response(status, response_headers)
    return ['Hello world!n']

Application side objects can be invoked multiple times, as all servers make such repeated requests.[3]

Server/Gateway Side

The server or gateway invokes the application callable once for each request it receives from an HTTP client, that is directed at the application.


The server side of WSGI simply receives requests from the HTTP client, invokes the application once for each request, and sends the response returned by the application to the client.

Example Websserver Configuration

A web server’s configuration specifies what requests should be passed to the WSGI server to process. Once a request is processed and generated by the WSGI server, the response is passed back through the web server and onto the browser[4].


For example, this Nginx web server’s configuration specifies that Nginx should handle static assets (such as images, JavaScript, and CSS files) under the /static directory and pass all other requests to the WSGI server running on port 8000. In this case, NGINX only works as a reverse proxy, it receives the requests and proxies them to the application server, that would be UWSGI.:

# this specifies that there is a WSGI server running on port 8000
upstream app_server_djangoapp {
    server localhost:8000 fail_timeout=0;
}

# Nginx is set up to run on the standard HTTP port and listen for requests
server {
  listen 80;

  # nginx should serve up static files and never send to the WSGI server
  location /static {
    autoindex on;
    alias /srv/www/assets;
  }

  # requests that do not fall under /static are passed on to the WSGI
  # server that was specified above running on port 8000
  location / {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_host;
    proxy_redirect off;

    if (!-f $request_filename) {
      proxy_pass http://app_server_djangoapp;
      break;
    }
  }
}

Closing

WSGI is a critical Python specification, but in day-to-day python development, most developers need not concern themselves with the low-level details of the specification. As long as they are using a major framework, they’ll benefit from WSGI without having to dig any deeper. Most developers don’t require an intimate knowledge of WSGI, because the specification has been implemented in all major Python frameworks.


That said, WSGI is still relevant, although it is not a prerequisite for Python web development. One notable exception involves software engineers who decide to work on Python frameworks rather than Python applications. As far as they are concerned, WSGI is an indispensable specification, and they have to know the ins and outs of WSGI if they hope to integrate it in their framework[3].

References

[1] https://www.python.org/dev/peps/pep-0333/
[2] https://www.appdynamics.com/blog/engineering/an-introduction-to-python-wsgi-servers-part-1/
[3] https://www.whoishostingthis.com/resources/wsgi/
[4] https://www.fullstackpython.com/wsgi-servers.html