wsgi, werkzeug and the challenges of building a web...

22
WSGI, Werkzeug And the challenges of building a web framework @igorgue

Upload: others

Post on 25-Sep-2020

5 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

WSGI WerkzeugAnd the challenges of

building a web frameworkigorgue

The Problems

bull A paradigm shift in web applications

bull More JavaScript (about 40 of our code base)

bull Applications are getting small

bull Backend is no longer so tied to the front end (no more crazy render of templates in the backend)

I want to write a Framework

bull Make it just talk REST

bull No ORM

bull No templates

bull Just a routing mechanism

bull httppappoprojectorg (started as a Haskell project)

My Goal

httpwebmachinebashocomimageshttp-headers-status-v3png

Hello World Time

WSGI

def13 hello_world(environ13 start_response)13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 World]

Run it but donrsquot

if13 __name__13 ==13 __main__13 13 13 13 from13 wsgirefsimple_server13 import13 make_server

13 13 13 13 host13 =13 localhost13 13 13 13 port13 =13 800013 13 13 13 server13 =13 make_server(host13 port13 hello_world)

13 13 13 13 print13 Server13 running13 on13 httphostportformat(host=host13 port=port)13 13 13 13 serverserve_forever()

Use a Webserver

mod_wsgi

Gunicorn

uWSGI

Gunicorn

$13 gunicorn13 modulemain_function_or_class

Or in our example

$13 gunicorn13 hello_worldhello_world13 if13 we13 have13 a13 hello_worldpy13 module

my personal favorite

Parsing Query String

def13 hello_world(environ13 start_response)13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

Dealing with the Pathdef13 hello_world(environ13 start_response)13 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 requested_path13 ==13 13 13 13 13 13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 13 13 13 13 else13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]13 13 13 13 elif13 requested_path13 ==13 lol13 or13 requested_path13 ==13 lol13 13 13 13 13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [LOL]13 13 13 13 else13 13 13 13 13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [Upps13 your13 requested13 path13 path13 was13 not13 foundformat(path=requested_path)]

Better Url Handlingdef13 hello(environ13 start_response)13 13 13 13 Says13 hello13 to13 the13 user13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

def13 lol(environ13 start_response)13 13 13 13 Just13 prints13 LOL13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [LOL]

def13 not_found(environ13 start_response)13 13 13 13 Shows13 a13 40413 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Resource13 path13 couldnt13 be13 foundformat(path=requested_path)]

Better Url Handling Matchingurls13 =13 [13 13 13 13 (r^$13 hello)13 13 13 13 (r^lol$13 lol)]

def13 application(environ13 start_response)13 13 13 13 13 13 13 13 WSGI13 application13 that13 will13 get13 served13 13 13 13 13 13 13 13 requested_path13 =13 environ[PATH_INFO]lstrip()

13 13 13 13 for13 regex13 callback13 in13 urls13 13 13 13 13 13 13 13 match13 =13 research(regex13 requested_path)

13 13 13 13 13 13 13 13 if13 match13 13 13 13 13 13 13 13 13 13 13 13 return13 callback(environ13 start_response)

13 13 13 13 return13 not_found(environ13 start_response)

Werkzeug

from13 werkzeugwrappers13 import13 Request13 Response

def13 hello_world(environ13 start_response)13 13 13 13 request13 =13 Request(environ)13 13 13 13 response13 =13 Response(Hello13 0format(requestargsget(name13 World)))

13 13 13 13 return13 response(environ13 start_response)

Routes

selfurl_map13 =13 Map([13 13 13 13 Rule(13 endpoint=index)13 13 13 13 Rule(ltnamegt13 endpoint=dashboard)13 13 13 13 Rule(ltnamegtinfo13 endpoint=contact_information)])

User Agent Queries

from13 werkzeugwrappers13 import13 Responsefrom13 werkzeuguseragents13 import13 UserAgent

def13 application(environ13 start_response)13 13 13 13 browser13 =13 UserAgent(environ)browser13 13 chrome13 13 13 13 response13 =13 Response(Hello13 browserformat(browser=browser))

13 13 13 13 return13 response(environ13 start_response)

Debugger Support

Debugger Shell

DeploymentltVirtualHost13 gt13 13 13 13 ServerName13 browserstuffdev

13 13 13 13 WSGIDaemonProcess13 browserstuff13 user=user113 group=group113 processes=213 threads=513 13 13 13 WSGIScriptAlias13 13 Usersigorcodewsgi_werkzeugwerkzeugappwsgi

13 13 13 13 ltDirectory13 Usersigorcodewsgi_werkzeugwerkzeuggt13 13 13 13 13 13 13 13 WSGIProcessGroup13 browserstuff13 13 13 13 13 13 13 13 WSGIApplicationGroup13 GLOBAL13 13 13 13 13 13 13 13 Order13 denyallow13 13 13 13 13 13 13 13 Allow13 from13 all13 13 13 13 ltDirectorygtltVirtualHostgt

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 2: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

The Problems

bull A paradigm shift in web applications

bull More JavaScript (about 40 of our code base)

bull Applications are getting small

bull Backend is no longer so tied to the front end (no more crazy render of templates in the backend)

I want to write a Framework

bull Make it just talk REST

bull No ORM

bull No templates

bull Just a routing mechanism

bull httppappoprojectorg (started as a Haskell project)

My Goal

httpwebmachinebashocomimageshttp-headers-status-v3png

Hello World Time

WSGI

def13 hello_world(environ13 start_response)13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 World]

Run it but donrsquot

if13 __name__13 ==13 __main__13 13 13 13 from13 wsgirefsimple_server13 import13 make_server

13 13 13 13 host13 =13 localhost13 13 13 13 port13 =13 800013 13 13 13 server13 =13 make_server(host13 port13 hello_world)

13 13 13 13 print13 Server13 running13 on13 httphostportformat(host=host13 port=port)13 13 13 13 serverserve_forever()

Use a Webserver

mod_wsgi

Gunicorn

uWSGI

Gunicorn

$13 gunicorn13 modulemain_function_or_class

Or in our example

$13 gunicorn13 hello_worldhello_world13 if13 we13 have13 a13 hello_worldpy13 module

my personal favorite

Parsing Query String

def13 hello_world(environ13 start_response)13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

Dealing with the Pathdef13 hello_world(environ13 start_response)13 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 requested_path13 ==13 13 13 13 13 13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 13 13 13 13 else13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]13 13 13 13 elif13 requested_path13 ==13 lol13 or13 requested_path13 ==13 lol13 13 13 13 13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [LOL]13 13 13 13 else13 13 13 13 13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [Upps13 your13 requested13 path13 path13 was13 not13 foundformat(path=requested_path)]

Better Url Handlingdef13 hello(environ13 start_response)13 13 13 13 Says13 hello13 to13 the13 user13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

def13 lol(environ13 start_response)13 13 13 13 Just13 prints13 LOL13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [LOL]

def13 not_found(environ13 start_response)13 13 13 13 Shows13 a13 40413 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Resource13 path13 couldnt13 be13 foundformat(path=requested_path)]

Better Url Handling Matchingurls13 =13 [13 13 13 13 (r^$13 hello)13 13 13 13 (r^lol$13 lol)]

def13 application(environ13 start_response)13 13 13 13 13 13 13 13 WSGI13 application13 that13 will13 get13 served13 13 13 13 13 13 13 13 requested_path13 =13 environ[PATH_INFO]lstrip()

13 13 13 13 for13 regex13 callback13 in13 urls13 13 13 13 13 13 13 13 match13 =13 research(regex13 requested_path)

13 13 13 13 13 13 13 13 if13 match13 13 13 13 13 13 13 13 13 13 13 13 return13 callback(environ13 start_response)

13 13 13 13 return13 not_found(environ13 start_response)

Werkzeug

from13 werkzeugwrappers13 import13 Request13 Response

def13 hello_world(environ13 start_response)13 13 13 13 request13 =13 Request(environ)13 13 13 13 response13 =13 Response(Hello13 0format(requestargsget(name13 World)))

13 13 13 13 return13 response(environ13 start_response)

Routes

selfurl_map13 =13 Map([13 13 13 13 Rule(13 endpoint=index)13 13 13 13 Rule(ltnamegt13 endpoint=dashboard)13 13 13 13 Rule(ltnamegtinfo13 endpoint=contact_information)])

User Agent Queries

from13 werkzeugwrappers13 import13 Responsefrom13 werkzeuguseragents13 import13 UserAgent

def13 application(environ13 start_response)13 13 13 13 browser13 =13 UserAgent(environ)browser13 13 chrome13 13 13 13 response13 =13 Response(Hello13 browserformat(browser=browser))

13 13 13 13 return13 response(environ13 start_response)

Debugger Support

Debugger Shell

DeploymentltVirtualHost13 gt13 13 13 13 ServerName13 browserstuffdev

13 13 13 13 WSGIDaemonProcess13 browserstuff13 user=user113 group=group113 processes=213 threads=513 13 13 13 WSGIScriptAlias13 13 Usersigorcodewsgi_werkzeugwerkzeugappwsgi

13 13 13 13 ltDirectory13 Usersigorcodewsgi_werkzeugwerkzeuggt13 13 13 13 13 13 13 13 WSGIProcessGroup13 browserstuff13 13 13 13 13 13 13 13 WSGIApplicationGroup13 GLOBAL13 13 13 13 13 13 13 13 Order13 denyallow13 13 13 13 13 13 13 13 Allow13 from13 all13 13 13 13 ltDirectorygtltVirtualHostgt

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 3: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

I want to write a Framework

bull Make it just talk REST

bull No ORM

bull No templates

bull Just a routing mechanism

bull httppappoprojectorg (started as a Haskell project)

My Goal

httpwebmachinebashocomimageshttp-headers-status-v3png

Hello World Time

WSGI

def13 hello_world(environ13 start_response)13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 World]

Run it but donrsquot

if13 __name__13 ==13 __main__13 13 13 13 from13 wsgirefsimple_server13 import13 make_server

13 13 13 13 host13 =13 localhost13 13 13 13 port13 =13 800013 13 13 13 server13 =13 make_server(host13 port13 hello_world)

13 13 13 13 print13 Server13 running13 on13 httphostportformat(host=host13 port=port)13 13 13 13 serverserve_forever()

Use a Webserver

mod_wsgi

Gunicorn

uWSGI

Gunicorn

$13 gunicorn13 modulemain_function_or_class

Or in our example

$13 gunicorn13 hello_worldhello_world13 if13 we13 have13 a13 hello_worldpy13 module

my personal favorite

Parsing Query String

def13 hello_world(environ13 start_response)13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

Dealing with the Pathdef13 hello_world(environ13 start_response)13 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 requested_path13 ==13 13 13 13 13 13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 13 13 13 13 else13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]13 13 13 13 elif13 requested_path13 ==13 lol13 or13 requested_path13 ==13 lol13 13 13 13 13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [LOL]13 13 13 13 else13 13 13 13 13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [Upps13 your13 requested13 path13 path13 was13 not13 foundformat(path=requested_path)]

Better Url Handlingdef13 hello(environ13 start_response)13 13 13 13 Says13 hello13 to13 the13 user13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

def13 lol(environ13 start_response)13 13 13 13 Just13 prints13 LOL13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [LOL]

def13 not_found(environ13 start_response)13 13 13 13 Shows13 a13 40413 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Resource13 path13 couldnt13 be13 foundformat(path=requested_path)]

Better Url Handling Matchingurls13 =13 [13 13 13 13 (r^$13 hello)13 13 13 13 (r^lol$13 lol)]

def13 application(environ13 start_response)13 13 13 13 13 13 13 13 WSGI13 application13 that13 will13 get13 served13 13 13 13 13 13 13 13 requested_path13 =13 environ[PATH_INFO]lstrip()

13 13 13 13 for13 regex13 callback13 in13 urls13 13 13 13 13 13 13 13 match13 =13 research(regex13 requested_path)

13 13 13 13 13 13 13 13 if13 match13 13 13 13 13 13 13 13 13 13 13 13 return13 callback(environ13 start_response)

13 13 13 13 return13 not_found(environ13 start_response)

Werkzeug

from13 werkzeugwrappers13 import13 Request13 Response

def13 hello_world(environ13 start_response)13 13 13 13 request13 =13 Request(environ)13 13 13 13 response13 =13 Response(Hello13 0format(requestargsget(name13 World)))

13 13 13 13 return13 response(environ13 start_response)

Routes

selfurl_map13 =13 Map([13 13 13 13 Rule(13 endpoint=index)13 13 13 13 Rule(ltnamegt13 endpoint=dashboard)13 13 13 13 Rule(ltnamegtinfo13 endpoint=contact_information)])

User Agent Queries

from13 werkzeugwrappers13 import13 Responsefrom13 werkzeuguseragents13 import13 UserAgent

def13 application(environ13 start_response)13 13 13 13 browser13 =13 UserAgent(environ)browser13 13 chrome13 13 13 13 response13 =13 Response(Hello13 browserformat(browser=browser))

13 13 13 13 return13 response(environ13 start_response)

Debugger Support

Debugger Shell

DeploymentltVirtualHost13 gt13 13 13 13 ServerName13 browserstuffdev

13 13 13 13 WSGIDaemonProcess13 browserstuff13 user=user113 group=group113 processes=213 threads=513 13 13 13 WSGIScriptAlias13 13 Usersigorcodewsgi_werkzeugwerkzeugappwsgi

13 13 13 13 ltDirectory13 Usersigorcodewsgi_werkzeugwerkzeuggt13 13 13 13 13 13 13 13 WSGIProcessGroup13 browserstuff13 13 13 13 13 13 13 13 WSGIApplicationGroup13 GLOBAL13 13 13 13 13 13 13 13 Order13 denyallow13 13 13 13 13 13 13 13 Allow13 from13 all13 13 13 13 ltDirectorygtltVirtualHostgt

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 4: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

My Goal

httpwebmachinebashocomimageshttp-headers-status-v3png

Hello World Time

WSGI

def13 hello_world(environ13 start_response)13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 World]

Run it but donrsquot

if13 __name__13 ==13 __main__13 13 13 13 from13 wsgirefsimple_server13 import13 make_server

13 13 13 13 host13 =13 localhost13 13 13 13 port13 =13 800013 13 13 13 server13 =13 make_server(host13 port13 hello_world)

13 13 13 13 print13 Server13 running13 on13 httphostportformat(host=host13 port=port)13 13 13 13 serverserve_forever()

Use a Webserver

mod_wsgi

Gunicorn

uWSGI

Gunicorn

$13 gunicorn13 modulemain_function_or_class

Or in our example

$13 gunicorn13 hello_worldhello_world13 if13 we13 have13 a13 hello_worldpy13 module

my personal favorite

Parsing Query String

def13 hello_world(environ13 start_response)13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

Dealing with the Pathdef13 hello_world(environ13 start_response)13 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 requested_path13 ==13 13 13 13 13 13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 13 13 13 13 else13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]13 13 13 13 elif13 requested_path13 ==13 lol13 or13 requested_path13 ==13 lol13 13 13 13 13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [LOL]13 13 13 13 else13 13 13 13 13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [Upps13 your13 requested13 path13 path13 was13 not13 foundformat(path=requested_path)]

Better Url Handlingdef13 hello(environ13 start_response)13 13 13 13 Says13 hello13 to13 the13 user13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

def13 lol(environ13 start_response)13 13 13 13 Just13 prints13 LOL13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [LOL]

def13 not_found(environ13 start_response)13 13 13 13 Shows13 a13 40413 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Resource13 path13 couldnt13 be13 foundformat(path=requested_path)]

Better Url Handling Matchingurls13 =13 [13 13 13 13 (r^$13 hello)13 13 13 13 (r^lol$13 lol)]

def13 application(environ13 start_response)13 13 13 13 13 13 13 13 WSGI13 application13 that13 will13 get13 served13 13 13 13 13 13 13 13 requested_path13 =13 environ[PATH_INFO]lstrip()

13 13 13 13 for13 regex13 callback13 in13 urls13 13 13 13 13 13 13 13 match13 =13 research(regex13 requested_path)

13 13 13 13 13 13 13 13 if13 match13 13 13 13 13 13 13 13 13 13 13 13 return13 callback(environ13 start_response)

13 13 13 13 return13 not_found(environ13 start_response)

Werkzeug

from13 werkzeugwrappers13 import13 Request13 Response

def13 hello_world(environ13 start_response)13 13 13 13 request13 =13 Request(environ)13 13 13 13 response13 =13 Response(Hello13 0format(requestargsget(name13 World)))

13 13 13 13 return13 response(environ13 start_response)

Routes

selfurl_map13 =13 Map([13 13 13 13 Rule(13 endpoint=index)13 13 13 13 Rule(ltnamegt13 endpoint=dashboard)13 13 13 13 Rule(ltnamegtinfo13 endpoint=contact_information)])

User Agent Queries

from13 werkzeugwrappers13 import13 Responsefrom13 werkzeuguseragents13 import13 UserAgent

def13 application(environ13 start_response)13 13 13 13 browser13 =13 UserAgent(environ)browser13 13 chrome13 13 13 13 response13 =13 Response(Hello13 browserformat(browser=browser))

13 13 13 13 return13 response(environ13 start_response)

Debugger Support

Debugger Shell

DeploymentltVirtualHost13 gt13 13 13 13 ServerName13 browserstuffdev

13 13 13 13 WSGIDaemonProcess13 browserstuff13 user=user113 group=group113 processes=213 threads=513 13 13 13 WSGIScriptAlias13 13 Usersigorcodewsgi_werkzeugwerkzeugappwsgi

13 13 13 13 ltDirectory13 Usersigorcodewsgi_werkzeugwerkzeuggt13 13 13 13 13 13 13 13 WSGIProcessGroup13 browserstuff13 13 13 13 13 13 13 13 WSGIApplicationGroup13 GLOBAL13 13 13 13 13 13 13 13 Order13 denyallow13 13 13 13 13 13 13 13 Allow13 from13 all13 13 13 13 ltDirectorygtltVirtualHostgt

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 5: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

Hello World Time

WSGI

def13 hello_world(environ13 start_response)13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 World]

Run it but donrsquot

if13 __name__13 ==13 __main__13 13 13 13 from13 wsgirefsimple_server13 import13 make_server

13 13 13 13 host13 =13 localhost13 13 13 13 port13 =13 800013 13 13 13 server13 =13 make_server(host13 port13 hello_world)

13 13 13 13 print13 Server13 running13 on13 httphostportformat(host=host13 port=port)13 13 13 13 serverserve_forever()

Use a Webserver

mod_wsgi

Gunicorn

uWSGI

Gunicorn

$13 gunicorn13 modulemain_function_or_class

Or in our example

$13 gunicorn13 hello_worldhello_world13 if13 we13 have13 a13 hello_worldpy13 module

my personal favorite

Parsing Query String

def13 hello_world(environ13 start_response)13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

Dealing with the Pathdef13 hello_world(environ13 start_response)13 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 requested_path13 ==13 13 13 13 13 13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 13 13 13 13 else13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]13 13 13 13 elif13 requested_path13 ==13 lol13 or13 requested_path13 ==13 lol13 13 13 13 13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [LOL]13 13 13 13 else13 13 13 13 13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [Upps13 your13 requested13 path13 path13 was13 not13 foundformat(path=requested_path)]

Better Url Handlingdef13 hello(environ13 start_response)13 13 13 13 Says13 hello13 to13 the13 user13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

def13 lol(environ13 start_response)13 13 13 13 Just13 prints13 LOL13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [LOL]

def13 not_found(environ13 start_response)13 13 13 13 Shows13 a13 40413 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Resource13 path13 couldnt13 be13 foundformat(path=requested_path)]

Better Url Handling Matchingurls13 =13 [13 13 13 13 (r^$13 hello)13 13 13 13 (r^lol$13 lol)]

def13 application(environ13 start_response)13 13 13 13 13 13 13 13 WSGI13 application13 that13 will13 get13 served13 13 13 13 13 13 13 13 requested_path13 =13 environ[PATH_INFO]lstrip()

13 13 13 13 for13 regex13 callback13 in13 urls13 13 13 13 13 13 13 13 match13 =13 research(regex13 requested_path)

13 13 13 13 13 13 13 13 if13 match13 13 13 13 13 13 13 13 13 13 13 13 return13 callback(environ13 start_response)

13 13 13 13 return13 not_found(environ13 start_response)

Werkzeug

from13 werkzeugwrappers13 import13 Request13 Response

def13 hello_world(environ13 start_response)13 13 13 13 request13 =13 Request(environ)13 13 13 13 response13 =13 Response(Hello13 0format(requestargsget(name13 World)))

13 13 13 13 return13 response(environ13 start_response)

Routes

selfurl_map13 =13 Map([13 13 13 13 Rule(13 endpoint=index)13 13 13 13 Rule(ltnamegt13 endpoint=dashboard)13 13 13 13 Rule(ltnamegtinfo13 endpoint=contact_information)])

User Agent Queries

from13 werkzeugwrappers13 import13 Responsefrom13 werkzeuguseragents13 import13 UserAgent

def13 application(environ13 start_response)13 13 13 13 browser13 =13 UserAgent(environ)browser13 13 chrome13 13 13 13 response13 =13 Response(Hello13 browserformat(browser=browser))

13 13 13 13 return13 response(environ13 start_response)

Debugger Support

Debugger Shell

DeploymentltVirtualHost13 gt13 13 13 13 ServerName13 browserstuffdev

13 13 13 13 WSGIDaemonProcess13 browserstuff13 user=user113 group=group113 processes=213 threads=513 13 13 13 WSGIScriptAlias13 13 Usersigorcodewsgi_werkzeugwerkzeugappwsgi

13 13 13 13 ltDirectory13 Usersigorcodewsgi_werkzeugwerkzeuggt13 13 13 13 13 13 13 13 WSGIProcessGroup13 browserstuff13 13 13 13 13 13 13 13 WSGIApplicationGroup13 GLOBAL13 13 13 13 13 13 13 13 Order13 denyallow13 13 13 13 13 13 13 13 Allow13 from13 all13 13 13 13 ltDirectorygtltVirtualHostgt

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 6: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

WSGI

def13 hello_world(environ13 start_response)13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 World]

Run it but donrsquot

if13 __name__13 ==13 __main__13 13 13 13 from13 wsgirefsimple_server13 import13 make_server

13 13 13 13 host13 =13 localhost13 13 13 13 port13 =13 800013 13 13 13 server13 =13 make_server(host13 port13 hello_world)

13 13 13 13 print13 Server13 running13 on13 httphostportformat(host=host13 port=port)13 13 13 13 serverserve_forever()

Use a Webserver

mod_wsgi

Gunicorn

uWSGI

Gunicorn

$13 gunicorn13 modulemain_function_or_class

Or in our example

$13 gunicorn13 hello_worldhello_world13 if13 we13 have13 a13 hello_worldpy13 module

my personal favorite

Parsing Query String

def13 hello_world(environ13 start_response)13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

Dealing with the Pathdef13 hello_world(environ13 start_response)13 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 requested_path13 ==13 13 13 13 13 13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 13 13 13 13 else13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]13 13 13 13 elif13 requested_path13 ==13 lol13 or13 requested_path13 ==13 lol13 13 13 13 13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [LOL]13 13 13 13 else13 13 13 13 13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [Upps13 your13 requested13 path13 path13 was13 not13 foundformat(path=requested_path)]

Better Url Handlingdef13 hello(environ13 start_response)13 13 13 13 Says13 hello13 to13 the13 user13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

def13 lol(environ13 start_response)13 13 13 13 Just13 prints13 LOL13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [LOL]

def13 not_found(environ13 start_response)13 13 13 13 Shows13 a13 40413 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Resource13 path13 couldnt13 be13 foundformat(path=requested_path)]

Better Url Handling Matchingurls13 =13 [13 13 13 13 (r^$13 hello)13 13 13 13 (r^lol$13 lol)]

def13 application(environ13 start_response)13 13 13 13 13 13 13 13 WSGI13 application13 that13 will13 get13 served13 13 13 13 13 13 13 13 requested_path13 =13 environ[PATH_INFO]lstrip()

13 13 13 13 for13 regex13 callback13 in13 urls13 13 13 13 13 13 13 13 match13 =13 research(regex13 requested_path)

13 13 13 13 13 13 13 13 if13 match13 13 13 13 13 13 13 13 13 13 13 13 return13 callback(environ13 start_response)

13 13 13 13 return13 not_found(environ13 start_response)

Werkzeug

from13 werkzeugwrappers13 import13 Request13 Response

def13 hello_world(environ13 start_response)13 13 13 13 request13 =13 Request(environ)13 13 13 13 response13 =13 Response(Hello13 0format(requestargsget(name13 World)))

13 13 13 13 return13 response(environ13 start_response)

Routes

selfurl_map13 =13 Map([13 13 13 13 Rule(13 endpoint=index)13 13 13 13 Rule(ltnamegt13 endpoint=dashboard)13 13 13 13 Rule(ltnamegtinfo13 endpoint=contact_information)])

User Agent Queries

from13 werkzeugwrappers13 import13 Responsefrom13 werkzeuguseragents13 import13 UserAgent

def13 application(environ13 start_response)13 13 13 13 browser13 =13 UserAgent(environ)browser13 13 chrome13 13 13 13 response13 =13 Response(Hello13 browserformat(browser=browser))

13 13 13 13 return13 response(environ13 start_response)

Debugger Support

Debugger Shell

DeploymentltVirtualHost13 gt13 13 13 13 ServerName13 browserstuffdev

13 13 13 13 WSGIDaemonProcess13 browserstuff13 user=user113 group=group113 processes=213 threads=513 13 13 13 WSGIScriptAlias13 13 Usersigorcodewsgi_werkzeugwerkzeugappwsgi

13 13 13 13 ltDirectory13 Usersigorcodewsgi_werkzeugwerkzeuggt13 13 13 13 13 13 13 13 WSGIProcessGroup13 browserstuff13 13 13 13 13 13 13 13 WSGIApplicationGroup13 GLOBAL13 13 13 13 13 13 13 13 Order13 denyallow13 13 13 13 13 13 13 13 Allow13 from13 all13 13 13 13 ltDirectorygtltVirtualHostgt

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 7: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

Run it but donrsquot

if13 __name__13 ==13 __main__13 13 13 13 from13 wsgirefsimple_server13 import13 make_server

13 13 13 13 host13 =13 localhost13 13 13 13 port13 =13 800013 13 13 13 server13 =13 make_server(host13 port13 hello_world)

13 13 13 13 print13 Server13 running13 on13 httphostportformat(host=host13 port=port)13 13 13 13 serverserve_forever()

Use a Webserver

mod_wsgi

Gunicorn

uWSGI

Gunicorn

$13 gunicorn13 modulemain_function_or_class

Or in our example

$13 gunicorn13 hello_worldhello_world13 if13 we13 have13 a13 hello_worldpy13 module

my personal favorite

Parsing Query String

def13 hello_world(environ13 start_response)13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

Dealing with the Pathdef13 hello_world(environ13 start_response)13 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 requested_path13 ==13 13 13 13 13 13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 13 13 13 13 else13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]13 13 13 13 elif13 requested_path13 ==13 lol13 or13 requested_path13 ==13 lol13 13 13 13 13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [LOL]13 13 13 13 else13 13 13 13 13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [Upps13 your13 requested13 path13 path13 was13 not13 foundformat(path=requested_path)]

Better Url Handlingdef13 hello(environ13 start_response)13 13 13 13 Says13 hello13 to13 the13 user13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

def13 lol(environ13 start_response)13 13 13 13 Just13 prints13 LOL13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [LOL]

def13 not_found(environ13 start_response)13 13 13 13 Shows13 a13 40413 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Resource13 path13 couldnt13 be13 foundformat(path=requested_path)]

Better Url Handling Matchingurls13 =13 [13 13 13 13 (r^$13 hello)13 13 13 13 (r^lol$13 lol)]

def13 application(environ13 start_response)13 13 13 13 13 13 13 13 WSGI13 application13 that13 will13 get13 served13 13 13 13 13 13 13 13 requested_path13 =13 environ[PATH_INFO]lstrip()

13 13 13 13 for13 regex13 callback13 in13 urls13 13 13 13 13 13 13 13 match13 =13 research(regex13 requested_path)

13 13 13 13 13 13 13 13 if13 match13 13 13 13 13 13 13 13 13 13 13 13 return13 callback(environ13 start_response)

13 13 13 13 return13 not_found(environ13 start_response)

Werkzeug

from13 werkzeugwrappers13 import13 Request13 Response

def13 hello_world(environ13 start_response)13 13 13 13 request13 =13 Request(environ)13 13 13 13 response13 =13 Response(Hello13 0format(requestargsget(name13 World)))

13 13 13 13 return13 response(environ13 start_response)

Routes

selfurl_map13 =13 Map([13 13 13 13 Rule(13 endpoint=index)13 13 13 13 Rule(ltnamegt13 endpoint=dashboard)13 13 13 13 Rule(ltnamegtinfo13 endpoint=contact_information)])

User Agent Queries

from13 werkzeugwrappers13 import13 Responsefrom13 werkzeuguseragents13 import13 UserAgent

def13 application(environ13 start_response)13 13 13 13 browser13 =13 UserAgent(environ)browser13 13 chrome13 13 13 13 response13 =13 Response(Hello13 browserformat(browser=browser))

13 13 13 13 return13 response(environ13 start_response)

Debugger Support

Debugger Shell

DeploymentltVirtualHost13 gt13 13 13 13 ServerName13 browserstuffdev

13 13 13 13 WSGIDaemonProcess13 browserstuff13 user=user113 group=group113 processes=213 threads=513 13 13 13 WSGIScriptAlias13 13 Usersigorcodewsgi_werkzeugwerkzeugappwsgi

13 13 13 13 ltDirectory13 Usersigorcodewsgi_werkzeugwerkzeuggt13 13 13 13 13 13 13 13 WSGIProcessGroup13 browserstuff13 13 13 13 13 13 13 13 WSGIApplicationGroup13 GLOBAL13 13 13 13 13 13 13 13 Order13 denyallow13 13 13 13 13 13 13 13 Allow13 from13 all13 13 13 13 ltDirectorygtltVirtualHostgt

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 8: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

Use a Webserver

mod_wsgi

Gunicorn

uWSGI

Gunicorn

$13 gunicorn13 modulemain_function_or_class

Or in our example

$13 gunicorn13 hello_worldhello_world13 if13 we13 have13 a13 hello_worldpy13 module

my personal favorite

Parsing Query String

def13 hello_world(environ13 start_response)13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

Dealing with the Pathdef13 hello_world(environ13 start_response)13 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 requested_path13 ==13 13 13 13 13 13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 13 13 13 13 else13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]13 13 13 13 elif13 requested_path13 ==13 lol13 or13 requested_path13 ==13 lol13 13 13 13 13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [LOL]13 13 13 13 else13 13 13 13 13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [Upps13 your13 requested13 path13 path13 was13 not13 foundformat(path=requested_path)]

Better Url Handlingdef13 hello(environ13 start_response)13 13 13 13 Says13 hello13 to13 the13 user13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

def13 lol(environ13 start_response)13 13 13 13 Just13 prints13 LOL13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [LOL]

def13 not_found(environ13 start_response)13 13 13 13 Shows13 a13 40413 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Resource13 path13 couldnt13 be13 foundformat(path=requested_path)]

Better Url Handling Matchingurls13 =13 [13 13 13 13 (r^$13 hello)13 13 13 13 (r^lol$13 lol)]

def13 application(environ13 start_response)13 13 13 13 13 13 13 13 WSGI13 application13 that13 will13 get13 served13 13 13 13 13 13 13 13 requested_path13 =13 environ[PATH_INFO]lstrip()

13 13 13 13 for13 regex13 callback13 in13 urls13 13 13 13 13 13 13 13 match13 =13 research(regex13 requested_path)

13 13 13 13 13 13 13 13 if13 match13 13 13 13 13 13 13 13 13 13 13 13 return13 callback(environ13 start_response)

13 13 13 13 return13 not_found(environ13 start_response)

Werkzeug

from13 werkzeugwrappers13 import13 Request13 Response

def13 hello_world(environ13 start_response)13 13 13 13 request13 =13 Request(environ)13 13 13 13 response13 =13 Response(Hello13 0format(requestargsget(name13 World)))

13 13 13 13 return13 response(environ13 start_response)

Routes

selfurl_map13 =13 Map([13 13 13 13 Rule(13 endpoint=index)13 13 13 13 Rule(ltnamegt13 endpoint=dashboard)13 13 13 13 Rule(ltnamegtinfo13 endpoint=contact_information)])

User Agent Queries

from13 werkzeugwrappers13 import13 Responsefrom13 werkzeuguseragents13 import13 UserAgent

def13 application(environ13 start_response)13 13 13 13 browser13 =13 UserAgent(environ)browser13 13 chrome13 13 13 13 response13 =13 Response(Hello13 browserformat(browser=browser))

13 13 13 13 return13 response(environ13 start_response)

Debugger Support

Debugger Shell

DeploymentltVirtualHost13 gt13 13 13 13 ServerName13 browserstuffdev

13 13 13 13 WSGIDaemonProcess13 browserstuff13 user=user113 group=group113 processes=213 threads=513 13 13 13 WSGIScriptAlias13 13 Usersigorcodewsgi_werkzeugwerkzeugappwsgi

13 13 13 13 ltDirectory13 Usersigorcodewsgi_werkzeugwerkzeuggt13 13 13 13 13 13 13 13 WSGIProcessGroup13 browserstuff13 13 13 13 13 13 13 13 WSGIApplicationGroup13 GLOBAL13 13 13 13 13 13 13 13 Order13 denyallow13 13 13 13 13 13 13 13 Allow13 from13 all13 13 13 13 ltDirectorygtltVirtualHostgt

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 9: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

Gunicorn

$13 gunicorn13 modulemain_function_or_class

Or in our example

$13 gunicorn13 hello_worldhello_world13 if13 we13 have13 a13 hello_worldpy13 module

my personal favorite

Parsing Query String

def13 hello_world(environ13 start_response)13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

Dealing with the Pathdef13 hello_world(environ13 start_response)13 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 requested_path13 ==13 13 13 13 13 13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 13 13 13 13 else13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]13 13 13 13 elif13 requested_path13 ==13 lol13 or13 requested_path13 ==13 lol13 13 13 13 13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [LOL]13 13 13 13 else13 13 13 13 13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [Upps13 your13 requested13 path13 path13 was13 not13 foundformat(path=requested_path)]

Better Url Handlingdef13 hello(environ13 start_response)13 13 13 13 Says13 hello13 to13 the13 user13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

def13 lol(environ13 start_response)13 13 13 13 Just13 prints13 LOL13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [LOL]

def13 not_found(environ13 start_response)13 13 13 13 Shows13 a13 40413 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Resource13 path13 couldnt13 be13 foundformat(path=requested_path)]

Better Url Handling Matchingurls13 =13 [13 13 13 13 (r^$13 hello)13 13 13 13 (r^lol$13 lol)]

def13 application(environ13 start_response)13 13 13 13 13 13 13 13 WSGI13 application13 that13 will13 get13 served13 13 13 13 13 13 13 13 requested_path13 =13 environ[PATH_INFO]lstrip()

13 13 13 13 for13 regex13 callback13 in13 urls13 13 13 13 13 13 13 13 match13 =13 research(regex13 requested_path)

13 13 13 13 13 13 13 13 if13 match13 13 13 13 13 13 13 13 13 13 13 13 return13 callback(environ13 start_response)

13 13 13 13 return13 not_found(environ13 start_response)

Werkzeug

from13 werkzeugwrappers13 import13 Request13 Response

def13 hello_world(environ13 start_response)13 13 13 13 request13 =13 Request(environ)13 13 13 13 response13 =13 Response(Hello13 0format(requestargsget(name13 World)))

13 13 13 13 return13 response(environ13 start_response)

Routes

selfurl_map13 =13 Map([13 13 13 13 Rule(13 endpoint=index)13 13 13 13 Rule(ltnamegt13 endpoint=dashboard)13 13 13 13 Rule(ltnamegtinfo13 endpoint=contact_information)])

User Agent Queries

from13 werkzeugwrappers13 import13 Responsefrom13 werkzeuguseragents13 import13 UserAgent

def13 application(environ13 start_response)13 13 13 13 browser13 =13 UserAgent(environ)browser13 13 chrome13 13 13 13 response13 =13 Response(Hello13 browserformat(browser=browser))

13 13 13 13 return13 response(environ13 start_response)

Debugger Support

Debugger Shell

DeploymentltVirtualHost13 gt13 13 13 13 ServerName13 browserstuffdev

13 13 13 13 WSGIDaemonProcess13 browserstuff13 user=user113 group=group113 processes=213 threads=513 13 13 13 WSGIScriptAlias13 13 Usersigorcodewsgi_werkzeugwerkzeugappwsgi

13 13 13 13 ltDirectory13 Usersigorcodewsgi_werkzeugwerkzeuggt13 13 13 13 13 13 13 13 WSGIProcessGroup13 browserstuff13 13 13 13 13 13 13 13 WSGIApplicationGroup13 GLOBAL13 13 13 13 13 13 13 13 Order13 denyallow13 13 13 13 13 13 13 13 Allow13 from13 all13 13 13 13 ltDirectorygtltVirtualHostgt

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 10: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

Parsing Query String

def13 hello_world(environ13 start_response)13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

Dealing with the Pathdef13 hello_world(environ13 start_response)13 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 requested_path13 ==13 13 13 13 13 13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 13 13 13 13 else13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]13 13 13 13 elif13 requested_path13 ==13 lol13 or13 requested_path13 ==13 lol13 13 13 13 13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [LOL]13 13 13 13 else13 13 13 13 13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [Upps13 your13 requested13 path13 path13 was13 not13 foundformat(path=requested_path)]

Better Url Handlingdef13 hello(environ13 start_response)13 13 13 13 Says13 hello13 to13 the13 user13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

def13 lol(environ13 start_response)13 13 13 13 Just13 prints13 LOL13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [LOL]

def13 not_found(environ13 start_response)13 13 13 13 Shows13 a13 40413 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Resource13 path13 couldnt13 be13 foundformat(path=requested_path)]

Better Url Handling Matchingurls13 =13 [13 13 13 13 (r^$13 hello)13 13 13 13 (r^lol$13 lol)]

def13 application(environ13 start_response)13 13 13 13 13 13 13 13 WSGI13 application13 that13 will13 get13 served13 13 13 13 13 13 13 13 requested_path13 =13 environ[PATH_INFO]lstrip()

13 13 13 13 for13 regex13 callback13 in13 urls13 13 13 13 13 13 13 13 match13 =13 research(regex13 requested_path)

13 13 13 13 13 13 13 13 if13 match13 13 13 13 13 13 13 13 13 13 13 13 return13 callback(environ13 start_response)

13 13 13 13 return13 not_found(environ13 start_response)

Werkzeug

from13 werkzeugwrappers13 import13 Request13 Response

def13 hello_world(environ13 start_response)13 13 13 13 request13 =13 Request(environ)13 13 13 13 response13 =13 Response(Hello13 0format(requestargsget(name13 World)))

13 13 13 13 return13 response(environ13 start_response)

Routes

selfurl_map13 =13 Map([13 13 13 13 Rule(13 endpoint=index)13 13 13 13 Rule(ltnamegt13 endpoint=dashboard)13 13 13 13 Rule(ltnamegtinfo13 endpoint=contact_information)])

User Agent Queries

from13 werkzeugwrappers13 import13 Responsefrom13 werkzeuguseragents13 import13 UserAgent

def13 application(environ13 start_response)13 13 13 13 browser13 =13 UserAgent(environ)browser13 13 chrome13 13 13 13 response13 =13 Response(Hello13 browserformat(browser=browser))

13 13 13 13 return13 response(environ13 start_response)

Debugger Support

Debugger Shell

DeploymentltVirtualHost13 gt13 13 13 13 ServerName13 browserstuffdev

13 13 13 13 WSGIDaemonProcess13 browserstuff13 user=user113 group=group113 processes=213 threads=513 13 13 13 WSGIScriptAlias13 13 Usersigorcodewsgi_werkzeugwerkzeugappwsgi

13 13 13 13 ltDirectory13 Usersigorcodewsgi_werkzeugwerkzeuggt13 13 13 13 13 13 13 13 WSGIProcessGroup13 browserstuff13 13 13 13 13 13 13 13 WSGIApplicationGroup13 GLOBAL13 13 13 13 13 13 13 13 Order13 denyallow13 13 13 13 13 13 13 13 Allow13 from13 all13 13 13 13 ltDirectorygtltVirtualHostgt

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 11: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

Dealing with the Pathdef13 hello_world(environ13 start_response)13 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 requested_path13 ==13 13 13 13 13 13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 13 13 13 13 else13 13 13 13 13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]13 13 13 13 elif13 requested_path13 ==13 lol13 or13 requested_path13 ==13 lol13 13 13 13 13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [LOL]13 13 13 13 else13 13 13 13 13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 13 13 13 13 return13 [Upps13 your13 requested13 path13 path13 was13 not13 foundformat(path=requested_path)]

Better Url Handlingdef13 hello(environ13 start_response)13 13 13 13 Says13 hello13 to13 the13 user13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

def13 lol(environ13 start_response)13 13 13 13 Just13 prints13 LOL13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [LOL]

def13 not_found(environ13 start_response)13 13 13 13 Shows13 a13 40413 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Resource13 path13 couldnt13 be13 foundformat(path=requested_path)]

Better Url Handling Matchingurls13 =13 [13 13 13 13 (r^$13 hello)13 13 13 13 (r^lol$13 lol)]

def13 application(environ13 start_response)13 13 13 13 13 13 13 13 WSGI13 application13 that13 will13 get13 served13 13 13 13 13 13 13 13 requested_path13 =13 environ[PATH_INFO]lstrip()

13 13 13 13 for13 regex13 callback13 in13 urls13 13 13 13 13 13 13 13 match13 =13 research(regex13 requested_path)

13 13 13 13 13 13 13 13 if13 match13 13 13 13 13 13 13 13 13 13 13 13 return13 callback(environ13 start_response)

13 13 13 13 return13 not_found(environ13 start_response)

Werkzeug

from13 werkzeugwrappers13 import13 Request13 Response

def13 hello_world(environ13 start_response)13 13 13 13 request13 =13 Request(environ)13 13 13 13 response13 =13 Response(Hello13 0format(requestargsget(name13 World)))

13 13 13 13 return13 response(environ13 start_response)

Routes

selfurl_map13 =13 Map([13 13 13 13 Rule(13 endpoint=index)13 13 13 13 Rule(ltnamegt13 endpoint=dashboard)13 13 13 13 Rule(ltnamegtinfo13 endpoint=contact_information)])

User Agent Queries

from13 werkzeugwrappers13 import13 Responsefrom13 werkzeuguseragents13 import13 UserAgent

def13 application(environ13 start_response)13 13 13 13 browser13 =13 UserAgent(environ)browser13 13 chrome13 13 13 13 response13 =13 Response(Hello13 browserformat(browser=browser))

13 13 13 13 return13 response(environ13 start_response)

Debugger Support

Debugger Shell

DeploymentltVirtualHost13 gt13 13 13 13 ServerName13 browserstuffdev

13 13 13 13 WSGIDaemonProcess13 browserstuff13 user=user113 group=group113 processes=213 threads=513 13 13 13 WSGIScriptAlias13 13 Usersigorcodewsgi_werkzeugwerkzeugappwsgi

13 13 13 13 ltDirectory13 Usersigorcodewsgi_werkzeugwerkzeuggt13 13 13 13 13 13 13 13 WSGIProcessGroup13 browserstuff13 13 13 13 13 13 13 13 WSGIApplicationGroup13 GLOBAL13 13 13 13 13 13 13 13 Order13 denyallow13 13 13 13 13 13 13 13 Allow13 from13 all13 13 13 13 ltDirectorygtltVirtualHostgt

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 12: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

Better Url Handlingdef13 hello(environ13 start_response)13 13 13 13 Says13 hello13 to13 the13 user13 13 13 13 parameters13 =13 parse_qs(environget(QUERY_STRING13 ))

13 13 13 13 if13 subject13 in13 parameters13 13 13 13 13 13 13 13 subject13 =13 escape(parameters[subject][0])13 13 13 13 else13 13 13 13 13 13 13 13 subject13 =13 World

13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Hello13 subjectformat(subject=subject)]

def13 lol(environ13 start_response)13 13 13 13 Just13 prints13 LOL13 13 13 13 start_response(20013 OK13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [LOL]

def13 not_found(environ13 start_response)13 13 13 13 Shows13 a13 40413 13 13 13 requested_path13 =13 environ[PATH_INFO]13 13 13 13 start_response(40413 NOT13 FOUND13 [(Content-shy‐Type13 textplain)])

13 13 13 13 return13 [Resource13 path13 couldnt13 be13 foundformat(path=requested_path)]

Better Url Handling Matchingurls13 =13 [13 13 13 13 (r^$13 hello)13 13 13 13 (r^lol$13 lol)]

def13 application(environ13 start_response)13 13 13 13 13 13 13 13 WSGI13 application13 that13 will13 get13 served13 13 13 13 13 13 13 13 requested_path13 =13 environ[PATH_INFO]lstrip()

13 13 13 13 for13 regex13 callback13 in13 urls13 13 13 13 13 13 13 13 match13 =13 research(regex13 requested_path)

13 13 13 13 13 13 13 13 if13 match13 13 13 13 13 13 13 13 13 13 13 13 return13 callback(environ13 start_response)

13 13 13 13 return13 not_found(environ13 start_response)

Werkzeug

from13 werkzeugwrappers13 import13 Request13 Response

def13 hello_world(environ13 start_response)13 13 13 13 request13 =13 Request(environ)13 13 13 13 response13 =13 Response(Hello13 0format(requestargsget(name13 World)))

13 13 13 13 return13 response(environ13 start_response)

Routes

selfurl_map13 =13 Map([13 13 13 13 Rule(13 endpoint=index)13 13 13 13 Rule(ltnamegt13 endpoint=dashboard)13 13 13 13 Rule(ltnamegtinfo13 endpoint=contact_information)])

User Agent Queries

from13 werkzeugwrappers13 import13 Responsefrom13 werkzeuguseragents13 import13 UserAgent

def13 application(environ13 start_response)13 13 13 13 browser13 =13 UserAgent(environ)browser13 13 chrome13 13 13 13 response13 =13 Response(Hello13 browserformat(browser=browser))

13 13 13 13 return13 response(environ13 start_response)

Debugger Support

Debugger Shell

DeploymentltVirtualHost13 gt13 13 13 13 ServerName13 browserstuffdev

13 13 13 13 WSGIDaemonProcess13 browserstuff13 user=user113 group=group113 processes=213 threads=513 13 13 13 WSGIScriptAlias13 13 Usersigorcodewsgi_werkzeugwerkzeugappwsgi

13 13 13 13 ltDirectory13 Usersigorcodewsgi_werkzeugwerkzeuggt13 13 13 13 13 13 13 13 WSGIProcessGroup13 browserstuff13 13 13 13 13 13 13 13 WSGIApplicationGroup13 GLOBAL13 13 13 13 13 13 13 13 Order13 denyallow13 13 13 13 13 13 13 13 Allow13 from13 all13 13 13 13 ltDirectorygtltVirtualHostgt

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 13: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

Better Url Handling Matchingurls13 =13 [13 13 13 13 (r^$13 hello)13 13 13 13 (r^lol$13 lol)]

def13 application(environ13 start_response)13 13 13 13 13 13 13 13 WSGI13 application13 that13 will13 get13 served13 13 13 13 13 13 13 13 requested_path13 =13 environ[PATH_INFO]lstrip()

13 13 13 13 for13 regex13 callback13 in13 urls13 13 13 13 13 13 13 13 match13 =13 research(regex13 requested_path)

13 13 13 13 13 13 13 13 if13 match13 13 13 13 13 13 13 13 13 13 13 13 return13 callback(environ13 start_response)

13 13 13 13 return13 not_found(environ13 start_response)

Werkzeug

from13 werkzeugwrappers13 import13 Request13 Response

def13 hello_world(environ13 start_response)13 13 13 13 request13 =13 Request(environ)13 13 13 13 response13 =13 Response(Hello13 0format(requestargsget(name13 World)))

13 13 13 13 return13 response(environ13 start_response)

Routes

selfurl_map13 =13 Map([13 13 13 13 Rule(13 endpoint=index)13 13 13 13 Rule(ltnamegt13 endpoint=dashboard)13 13 13 13 Rule(ltnamegtinfo13 endpoint=contact_information)])

User Agent Queries

from13 werkzeugwrappers13 import13 Responsefrom13 werkzeuguseragents13 import13 UserAgent

def13 application(environ13 start_response)13 13 13 13 browser13 =13 UserAgent(environ)browser13 13 chrome13 13 13 13 response13 =13 Response(Hello13 browserformat(browser=browser))

13 13 13 13 return13 response(environ13 start_response)

Debugger Support

Debugger Shell

DeploymentltVirtualHost13 gt13 13 13 13 ServerName13 browserstuffdev

13 13 13 13 WSGIDaemonProcess13 browserstuff13 user=user113 group=group113 processes=213 threads=513 13 13 13 WSGIScriptAlias13 13 Usersigorcodewsgi_werkzeugwerkzeugappwsgi

13 13 13 13 ltDirectory13 Usersigorcodewsgi_werkzeugwerkzeuggt13 13 13 13 13 13 13 13 WSGIProcessGroup13 browserstuff13 13 13 13 13 13 13 13 WSGIApplicationGroup13 GLOBAL13 13 13 13 13 13 13 13 Order13 denyallow13 13 13 13 13 13 13 13 Allow13 from13 all13 13 13 13 ltDirectorygtltVirtualHostgt

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 14: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

Werkzeug

from13 werkzeugwrappers13 import13 Request13 Response

def13 hello_world(environ13 start_response)13 13 13 13 request13 =13 Request(environ)13 13 13 13 response13 =13 Response(Hello13 0format(requestargsget(name13 World)))

13 13 13 13 return13 response(environ13 start_response)

Routes

selfurl_map13 =13 Map([13 13 13 13 Rule(13 endpoint=index)13 13 13 13 Rule(ltnamegt13 endpoint=dashboard)13 13 13 13 Rule(ltnamegtinfo13 endpoint=contact_information)])

User Agent Queries

from13 werkzeugwrappers13 import13 Responsefrom13 werkzeuguseragents13 import13 UserAgent

def13 application(environ13 start_response)13 13 13 13 browser13 =13 UserAgent(environ)browser13 13 chrome13 13 13 13 response13 =13 Response(Hello13 browserformat(browser=browser))

13 13 13 13 return13 response(environ13 start_response)

Debugger Support

Debugger Shell

DeploymentltVirtualHost13 gt13 13 13 13 ServerName13 browserstuffdev

13 13 13 13 WSGIDaemonProcess13 browserstuff13 user=user113 group=group113 processes=213 threads=513 13 13 13 WSGIScriptAlias13 13 Usersigorcodewsgi_werkzeugwerkzeugappwsgi

13 13 13 13 ltDirectory13 Usersigorcodewsgi_werkzeugwerkzeuggt13 13 13 13 13 13 13 13 WSGIProcessGroup13 browserstuff13 13 13 13 13 13 13 13 WSGIApplicationGroup13 GLOBAL13 13 13 13 13 13 13 13 Order13 denyallow13 13 13 13 13 13 13 13 Allow13 from13 all13 13 13 13 ltDirectorygtltVirtualHostgt

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 15: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

Routes

selfurl_map13 =13 Map([13 13 13 13 Rule(13 endpoint=index)13 13 13 13 Rule(ltnamegt13 endpoint=dashboard)13 13 13 13 Rule(ltnamegtinfo13 endpoint=contact_information)])

User Agent Queries

from13 werkzeugwrappers13 import13 Responsefrom13 werkzeuguseragents13 import13 UserAgent

def13 application(environ13 start_response)13 13 13 13 browser13 =13 UserAgent(environ)browser13 13 chrome13 13 13 13 response13 =13 Response(Hello13 browserformat(browser=browser))

13 13 13 13 return13 response(environ13 start_response)

Debugger Support

Debugger Shell

DeploymentltVirtualHost13 gt13 13 13 13 ServerName13 browserstuffdev

13 13 13 13 WSGIDaemonProcess13 browserstuff13 user=user113 group=group113 processes=213 threads=513 13 13 13 WSGIScriptAlias13 13 Usersigorcodewsgi_werkzeugwerkzeugappwsgi

13 13 13 13 ltDirectory13 Usersigorcodewsgi_werkzeugwerkzeuggt13 13 13 13 13 13 13 13 WSGIProcessGroup13 browserstuff13 13 13 13 13 13 13 13 WSGIApplicationGroup13 GLOBAL13 13 13 13 13 13 13 13 Order13 denyallow13 13 13 13 13 13 13 13 Allow13 from13 all13 13 13 13 ltDirectorygtltVirtualHostgt

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 16: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

User Agent Queries

from13 werkzeugwrappers13 import13 Responsefrom13 werkzeuguseragents13 import13 UserAgent

def13 application(environ13 start_response)13 13 13 13 browser13 =13 UserAgent(environ)browser13 13 chrome13 13 13 13 response13 =13 Response(Hello13 browserformat(browser=browser))

13 13 13 13 return13 response(environ13 start_response)

Debugger Support

Debugger Shell

DeploymentltVirtualHost13 gt13 13 13 13 ServerName13 browserstuffdev

13 13 13 13 WSGIDaemonProcess13 browserstuff13 user=user113 group=group113 processes=213 threads=513 13 13 13 WSGIScriptAlias13 13 Usersigorcodewsgi_werkzeugwerkzeugappwsgi

13 13 13 13 ltDirectory13 Usersigorcodewsgi_werkzeugwerkzeuggt13 13 13 13 13 13 13 13 WSGIProcessGroup13 browserstuff13 13 13 13 13 13 13 13 WSGIApplicationGroup13 GLOBAL13 13 13 13 13 13 13 13 Order13 denyallow13 13 13 13 13 13 13 13 Allow13 from13 all13 13 13 13 ltDirectorygtltVirtualHostgt

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 17: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

Debugger Support

Debugger Shell

DeploymentltVirtualHost13 gt13 13 13 13 ServerName13 browserstuffdev

13 13 13 13 WSGIDaemonProcess13 browserstuff13 user=user113 group=group113 processes=213 threads=513 13 13 13 WSGIScriptAlias13 13 Usersigorcodewsgi_werkzeugwerkzeugappwsgi

13 13 13 13 ltDirectory13 Usersigorcodewsgi_werkzeugwerkzeuggt13 13 13 13 13 13 13 13 WSGIProcessGroup13 browserstuff13 13 13 13 13 13 13 13 WSGIApplicationGroup13 GLOBAL13 13 13 13 13 13 13 13 Order13 denyallow13 13 13 13 13 13 13 13 Allow13 from13 all13 13 13 13 ltDirectorygtltVirtualHostgt

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 18: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

Debugger Shell

DeploymentltVirtualHost13 gt13 13 13 13 ServerName13 browserstuffdev

13 13 13 13 WSGIDaemonProcess13 browserstuff13 user=user113 group=group113 processes=213 threads=513 13 13 13 WSGIScriptAlias13 13 Usersigorcodewsgi_werkzeugwerkzeugappwsgi

13 13 13 13 ltDirectory13 Usersigorcodewsgi_werkzeugwerkzeuggt13 13 13 13 13 13 13 13 WSGIProcessGroup13 browserstuff13 13 13 13 13 13 13 13 WSGIApplicationGroup13 GLOBAL13 13 13 13 13 13 13 13 Order13 denyallow13 13 13 13 13 13 13 13 Allow13 from13 all13 13 13 13 ltDirectorygtltVirtualHostgt

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 19: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

DeploymentltVirtualHost13 gt13 13 13 13 ServerName13 browserstuffdev

13 13 13 13 WSGIDaemonProcess13 browserstuff13 user=user113 group=group113 processes=213 threads=513 13 13 13 WSGIScriptAlias13 13 Usersigorcodewsgi_werkzeugwerkzeugappwsgi

13 13 13 13 ltDirectory13 Usersigorcodewsgi_werkzeugwerkzeuggt13 13 13 13 13 13 13 13 WSGIProcessGroup13 browserstuff13 13 13 13 13 13 13 13 WSGIApplicationGroup13 GLOBAL13 13 13 13 13 13 13 13 Order13 denyallow13 13 13 13 13 13 13 13 Allow13 from13 all13 13 13 13 ltDirectorygtltVirtualHostgt

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 20: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

Deploy Gunicorn with Supervisord

[programgunicorn]command=pathtogunicorn13 mainapplication13 -shy‐c13 pathtogunicornconfpydirectory=pathtoprojectuser=nobodyautostart=trueautorestart=trueredirect_stderr=True

httpsgithubcombenoitcgunicornblobmasterexamplessupervisorconf

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 21: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

Recap

bull WSGI isnrsquot hard

bull Werkzeug gives you a lot of the base

bull Stuff that Django doesnrsquot even have

bull Make your dreams come true and you might be the next DHH

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf

Page 22: WSGI, Werkzeug And the challenges of building a web frameworkigorgue.com/presentations/wsgi-werkzeug.pdf · WSGI def hello_world(environ,start_response): start_response( '200OK' ,[(

Thanks

httphackdayfoundationorg 2K prize

httpsenzaricom wersquore hiring

Steal thishttpigorguecompresentationswsgi-werkzeugpdf