The Simplest WSGI Middleware2019-05-27
apig-wsgi bridges between AWS API Gateway’s JSON format for HTTP requests and Python WSGI applications.
Recently Théophile Chevalier opened an issue requesting the library add an extra WSGI environ variable.
I closed it by pointing out that it’s not much code to add a custom WSGI middleware to do so (plus the exact key is a bit out of scope for the library).
I guess most Python web developers don’t touch WSGI day to day, so I figured I’d write this short post to share the knowledge.
A Quick Shot of WSGI
The WSGI specification defines an application as a callable takes two positional parameters. These parameters are, with their conventional names:
environ, a dict of variables that describe the HTTP request.
start_response, a function to call to call to start generation of the HTTP response.
The application is called for each request, should call
start_response and then return an iterable representing the contents of the HTTP response body.
There’s a lot of specification around this, but to implement the simplest middleware we don’t need to dive into that.
We want to only change
environ and pass everything on to the proxied application.
If we have
original_app pointing to our base WSGI application, we can make our wrapped application as a function like so:
Keys in a WSGI
environ with the pattern
HTTP_* represent the request’s HTTP headers, so this middleware adds the header “foo” with value “bar”.
It could do something more useful, for example in the issue I linked, Théophile wanted to set the
SCRIPT_NAME key, which represents the start of the URL’s path.
wrapped_app we would just need to update our host server configuration (say
apig-wsgi) to use
wrapped_app rather than
Of course, you could name these something else.
In a Full Application
To test this, I added it to a single file Django application based on the template I shared previously. I ran it with Python 3.7 and Django 2.2. Here’s the code:
The implementation uses a few things:
WSGI_APPLICATIONsetting is set to tell Django’s development server to use
appin the current module. Without this, Django would use its default WSGI application.
- A single view,
index, to echo back the contents of the HTTP header “foo”. (Using Django 2.2’s new
get_wsgi_application()to get Django’s default WSGI application, stored in
appis created as our wrapper as in the previous example.
DEBUG=1 python app.py runserver and visit the server, and you will see the magical output
WSGI middleware gets more complicated if you want to do anything to modify the response. It’s easier to create it as a class then.
For more information check out Graham Dumpleton’s post that shows an example full middleware implementation. There’s also a lot of community information linked on the WSGI official site’s learning section.
Are your Django project's tests slow? Read Speed Up Your Django Tests now!
One summary email a week, no spam, I pinky promise.
- Django versus Flask with Single File Applications
- A Single File Asynchronous Django Application
- Feature Checking versus Version Checking
© 2020 All rights reserved.