[Web-SIG] Comments/stylistic ideas regarding WSGI

Phillip J. Eby pje at telecommunity.com
Mon Aug 23 07:52:35 CEST 2004

At 12:44 AM 8/23/04 -0400, angryhicKclown at netscape.net wrote:
>Now that I understand what WSGI is intended to be used for, I like it a 
>lot. However, I do have a few suggestions.
>Although it means more typing, I think the API is too cryptic as-is.

So, now that you understand the API, you think it's too cryptic.  :)

All kidding aside, I've made some attempts to make the spec more readable 
with respect to the various callables, as you'll see in my next draft posting.

>I think that applications should be callable, but should have a single 
>parameter: gateway. The gateway parameter contains attributes and methods 
>such as environ, start_response(), and write(). This way, it's clear to 
>the end-user both in documentation (removing many instances of "callable" 
>and confusion with __init__) and also is very much more natural to many 

I agree that it's more natural, but I disagree that "naturalness" is an 
important goal for the WSGI spec.  The reason is that most of WSGI's 
initial audience will be implementing exactly *one* server/gateway and/or 
application, in order to add support for it to their server or application 
framework.  They will thus have "spec in hand" when implementing.  It's 
more important that they be able to easily implement the spec.

The second audience for WSGI will be people creating "middleware" 
components, and they will appreciate the bare-bones nature of WSGI even 
more, because they will not need to implement a "gateway" class in order to 
intercept inputs, outputs, or variables.  Many fairly sophisticated pieces 
of middleware will be written as a single function (maybe with one or two 
nested functions).

Best of all, these functions will be *very* explicit as to what they are 
modifying, because they will not contain code that's needed to emulate 
functions they aren't replacing.  Using multi-functional objects like your 
"gateway" proposal means that middleware components have to implement the 
full gateway interface.

>Finally, I think the most important reason this change should be 
>implemented is because it allows the interface to be easily upgraded 
>without breaking compatibility with older versions.

Actually, the current interface includes *numerous* routes for extension, 
including additional 'wsgi.' keys, and keyword arguments to callables.

>  Perhaps (just an example), in the future, there will be a need for a 
> flush() method, in addition to the write() method. In the current 
> version, start_response() would return a tuple of write() and flush(), 
> which would break current compatibility. The only other way I see of 
> doing this using the current spec would be passing a default parameter of 
> the version of the API used, which is ugly.

It would be simple to add a 'wsgi.flush' key to the environ to supply this 
functionality, were it needed.  (Of course, flush() isn't actually needed, 
because WSGI requires write buffers to always be emptied ASAP.)

>In my opinion, my proposal looks a bit clearer.

I agree with you, but as I said, it's not a primary goal.  WSGI will rarely 
be used directly by an application developer; it's much more likely that 
you will use some other Python Web API layered atop WSGI.  In other words, 
the intended audience is developers of servers, frameworks, and 
middleware.  And most framework and server authors will only code to the 
spec once, probably with the spec in hand so they can check their 
compliance.  I think it's better for them to have an absolutely unequivocal 
spec, that's simple to implement and easy to verify the correctness 
of.  For example, did you use a dictionary?  That's a trivial yes-or-no 
thing to check, compared to, e.g., "did I implement a sufficiently 
dictionary-like object?"

>My other idea (which follows the previous proposal) is to scrap 
>start_response() entirely, and instead set gateway.status and 
>gateway.headers attributes. The simple app would now look like:
>     def simple_app(gateway):
>         gateway.status = '200 OK'
>         gateway.headers = [('Content-type','text/plain')] # perhaps 
> gateway.set_header('Content-type','text/plain')?
>         gateway.write('Hello world!\n')

To properly evaluate your proposal, it's inappropriate to use the 
application-side code as a basis for comparison.  Compare the *server-side* 
code, and the code needed to implement various forms of middleware.  You 
will find that the relatively small gain on the application-side code is 
*rapidly* counterbalanced by the expanding complexity of servers and 
middleware.  For example, to implement a middleware component that applies 
an XSLT stylesheet, you'll need to create a class that implements all the 
WSGI methods, and delegates the ones it doesn't need to the previous 
gateway object.  It will also need properties so it can observe the setting 
of status and headers, and delegate those as well, while tracking what it 

By comparison, the functional architecture of WSGI allows a middleware 
component to simply pass through to the next component whatever it doesn't 
need to change.  For example, a middleware component for applying an XSLT 
stylesheet would only need to define 'start_response' and 'write' 
replacements, where the 'start_response' simply munged the headers for 
content type and length, and the 'write' would pump data into the 
stylesheet mechanism, and call the old write function with any output.

These changes are clearly connected to the functionality: there is no 
overhead being added just so the next component downstream gets a more 
"object-oriented" interface.

(I'm wondering if I should add any of this to the spec, but it already has 
a paragraph in the Rationale section saying the API is intentionally 
no-frills, and another one in the Q&A saying "Why is this interface so 
low-level?".  I'm not sure how much more I can add without it seeming 
overdefensive, although I'm sure I'll get ten times as many more "why don't 
you use an object" protests once this hits c.l.py.  Oh well.)

More information about the Web-SIG mailing list