Web applications are just interfaces
Browsers are ubiquitous GUI frameworks (tk sucks)
Managing cloud operations (beats screen sessions)
WSGI is a PEP. (You want to know them all, right?)
Some people pronounce it "Whiz-gi".
(rhymes with whiskey)
I don't.
HTTP is simple in theory.
Accept a socket connection
Parse request payload
Generate response
Buffer response payload
Close socket
POST /articles HTTP/1.1
User-Agent: my-awesome-client/1.3
Content-Type: application/json
Content-Length: 49
Host: www.myblog.com
Accept: */*
{"title": "foobar", "content": "This is a post."}
HTTP/1.1 201 Created
Date: Wed, 10 Jul 2013 02:03:00 GMT
Expires: -1
Content-Type: application/json
Content-Length: 37
{"status": 201, "message": "created"}
sock = socket(AF_INET, SOCK_STREAM)
sock.bind(("", 8080))
sock.listen(5)
while True:
(client, address) = sock.accept()
body = client.recv(BUFFER_SIZE)
while "\r\n\r\n" not in body:
body += client.recv(BUFFER_SIZE)
headers, body = body.split("\r\n\r\n")
method, path, headers = extract_headers(headers)
content_length = int(headers["content-length"]) - len(body)
if content_length:
body += client.recv(content_length - len(body))
client.send(handle_request(method, path, headers, body))
client.close()
The year was 2003...
The dark ages of Python on the web.
Everybody rolled their own thing.
Twisted Web, Zope, Webware, etc.
Custom servers, CGI, "proprietary" middleware...
Open-source vendor lock in
Took cues from Java servlet standardization
Minimal design implications for existing frameworks
Extensible for future hotness
Easy to understand / work with for (early) adopters.
The most basic app just takes two arguments.
environ
is a dictionary of request informationstart_response
handles... starting the response.
def application(environment, start_response):
status = "200 OK"
headers = [("Content-Type", "application/json")]
body = json.dumps({"status": 200, "message": "ok"})
start_response(status, headers)
yield body
environ
contains... a lot.
Some of the more valuable entries in environ
Raw WSGI makes simple apps very easy
Makes complex apps... interesting.
Most modern frameworks support this at the core.
Most abstract away the application itself.
Request and response objects, templating...
Really, WSGI enables frameworks.
Abstract container, support custom interfaces.
Most basic are wrappers like WebOb and Werkzeug
Simple frameworks like Flask to monsters like Django.
There are a lot of pieces out there.
Use what you know, or what you want to learn.
Jinja2, Cheetah, Mako, etc. for templates.
SQLAlchemy, Storm, MongoEngine, etc. for models.
Werkzeug, custom regex, etc. for routing.
It's hard to find a framework that DOESN'T.
Your usage may constrain what frameworks to use.
Limited dependencies? Raw WSGI.
Simple APIs? Flask.
Content management / massive app? Django.
One of the more powerful aspects of WSGI
You can nest apps.
Environ can be modified.
You can call start_response multiple times.
This means, you can intercept and change things.
def proxy_host(app):
def proxy_app(environ, start_response):
if "HTTP_X_FORWARDED" in environ:
environ["REMOTE_ADDR"] = environ["HTTP_X_FORWARDED"]
return app(environ, start_response)
return proxy_app
@proxy_host
def application(environ, start_response):
# do actual stuff...
Some WSGI adapters extend functionality.
# wrapped with gevent's websocket handler
def websocket_app(environ, start_response):
socket = environ["wsgi.websocket"]
socket.send(json.dumps({"foo": "bar"})
There are LOTS of WSGI deployment options.
gevent, mod_wsgi, gunicorn, cgi...
Depends on what you want to do.
Frequently middleware will be involved.
For development ONLY
from wsgiref.simple_server import make_server
def app(environ, start_response):
start_response("200 OK", [("Content-Type", "text/json")])
yield "Hello World!"
server = make_server("", 8000, app)
server.serve_forever()
IF you want to do raw WSGI... wsgiref
Werkzeug utilities are very helpful
Heroku deployment is easy here.
@joshmarshall on the Twitters.
@joshmarshall on the GitHub.