1
**************************
2
An Introduction to Restish
3
**************************
5
Restish is a simple to use, lightweight WSGI web framework and library with a
6
strong focus on resources, request/response, URLs and content negotiation.
7
Restish has very few dependencies and does not assume any particular templating
10
A key feature of Restish is that it makes no use of thread-locals or any other
11
concurrency-dependent contexts and so works equally well under
12
`Paste Deploy <http://pythonpaste.org/deploy/>`_ or a thread-less web server such
13
as `Spawning <http://pypi.python.org/pypi/Spawning>`_.
22
We were looking around for a web framework for a new project. Previously we had
23
worked with Twisted and Nevow and had developed the Formal form handling
24
library for it. However for this project we wanted something that would be a
25
little more accessible and that would allow us to make use of the full range of
26
libraries Python has to offer.
28
The three obvious frameworks were Pylons, TurboGears and Django. We wanted to
29
use SQLAlchemy and hence Django wasn't really a contender. TurboGears looked in
30
a state of flux and we were looking for something a lot lower level. So by
31
process of elimination we had to look at Pylons.
33
Pylons started out looking quite good but we started to find the odd problem.
34
The initial problem was Pylon's use of threadlocals. Using threadlocals
35
precludes any use of single threaded servers. So we removed threadlocals. Next
36
we started to make pylons more templating agnostic, eventually removing
37
templating completely. Finally, when we had removed all trace of pylons, we
38
realised what we had was a new lightweight web framework.
40
Advantages & Disadvantages
41
--------------------------
43
The advantages that restish has are
45
* Well tested and powerful url handling, parsing and creation
46
* Simple integration with templating frameworks
47
* Powerful but simple http request and response handling
49
The three libraries we have used in the creation of restsh are paste (for
50
initial project template creation), decorator (used to decorate methods as
51
children or http handlers and for adding page templating) and webob (for it's
52
http.request and response)
54
Executive Summary for Coders
55
----------------------------
57
.. code-block:: python
59
# implicit resource locator
61
def blog(self, request, segments):
64
# explicit resource locator
65
@resource.child('blog')
66
def whatever(self, request, segments):
69
# templated resource locator
70
@resource.child('blog/{entry}')
71
def whatever(self, request, segments, entry=None):
72
return BlogEntry(entry)
74
# templated resource locator with partial match
75
@resource.child('blog/entry-{id}')
76
def whatever(self, request, segments, id=None):
79
# accept anything and return a 200 OK with content
81
def html(self, request):
82
return http.ok([('Content-Type','text/html')], '<p>Hello Wolrd</p>' )
84
# match json only and return 200 OK (system works out content type)
85
@resource.GET(accept='text/json')
86
def json(self, request):
87
return http.ok( [], '{"foo": "bar"}' )
89
# short cut for accept code
90
@resource.GET(accept='json')
91
def json(self, request):
92
return http.ok( [], simplejson.dumps({'foo': 'bar'}) )
94
# accept html and build a template explicitly
95
@resource.GET(accept='text/html')
96
def html(self, request):
97
content = templating.render(request, 'mytemplate.html', {'name': 'Tim'})
98
return http.ok( [('Content-Type','text/html')], content )
100
# short cut accept html and use templating decorator
101
@resource.GET(accept='html')
102
@templating.page('mypage.html')
103
def html(self, request):
104
return {'name': 'Tim'}
106
# accept anything and use url module to build a redirect
108
def html(self, request):
109
current_url = request.url.path_qs
110
return http.see_other( current_url.child('othersegment') )
112
# match a search pattern and redirect to google
113
@resource.child('search/{query}')
114
def search(self, request, segments, query=''):
115
google_url = url("http://google.com")
116
http.see_other( google_url.add_query('u',query) )
119
How to start a restish project
120
==============================
122
.. note:: Restish doesn't make you structure your project in any particular way but we've encapsulated our way of working in a paste script
127
First you use paste with a 'restish' template::
129
$ paster create --template=restish
131
This will create a basic, minimal restish project::
133
paster create --template=restish
134
Selected and implied templates:
135
restish#restish Template for creating a basic Restish package
136
Enter project name: myproject
141
Creating template restish
142
Creating directory ./myproject
143
Recursing into +package+
144
Creating ./myproject/myproject/
145
Copying __init__.py to ./myproject/myproject/__init__.py
147
Creating ./myproject/myproject/lib/
148
Copying __init__.py to ./myproject/myproject/lib/__init__.py
149
Copying guard.py to ./myproject/myproject/lib/guard.py
150
Copying templating.py_tmpl to ./myproject/myproject/lib/templating.py
151
Recursing into public
152
Creating ./myproject/myproject/public/
153
Copying index.html_tmpl to ./myproject/myproject/public/index.html
154
Recursing into resource
155
Creating ./myproject/myproject/resource/
156
Copying __init__.py to ./myproject/myproject/resource/__init__.py
157
Copying root.py_tmpl to ./myproject/myproject/resource/root.py
158
Copying wsgiapp.py_tmpl to ./myproject/myproject/wsgiapp.py
159
Copying +package+.ini_tmpl to ./myproject/myproject.ini
160
Copying development.ini_tmpl to ./myproject/development.ini
161
Copying live.ini_tmpl to ./myproject/live.ini
162
Copying setup.py_tmpl to ./myproject/setup.py
163
Running /Users/timparkin/py/bin/python setup.py egg_info
164
Manually creating paster_plugins.txt (deprecated! pass a paster_plugins keyword to setup() instead)
165
Adding Restish to paster_plugins.txt
168
What is in the template project
169
-------------------------------
171
The files in this project are as follows::
181
| | `-- templating.py
188
|-- myproject.egg-info
191
| |-- dependency_links.txt
192
| |-- entry_points.txt
194
| |-- paster_plugins.txt
200
We'll simplify that a bit by removing __init__'s and packaging files..::
210
| | `-- templating.py
220
The ini files are paste script configuration files and setup up the project. There is
221
a base configuration file that contains project settings and then there are two
222
deployment files, live and development, which contain information on how to
225
The ``lib`` directory
226
^^^^^^^^^^^^^^^^^^^^^
228
The lib directory has an example authenticator called 'guard.py' (which you can
229
ignore until needed) and a sample templating package which shows how to setup
230
templating with Mako, Genshi or Jinja.
232
We tend to put most of our project library code in here.
234
The ``public`` directory
235
^^^^^^^^^^^^^^^^^^^^^^^^
237
The public directory is used to serve static resources in preference to any
238
dynamic resources. The sample index.html just contains some information on what
241
A typical use for this would be to have a css, images and js directory
242
underneath with your assets in. Placing files directly inside public will also
243
make them available on root of your website, useful for favicons, google
244
analytics files, etc.
246
.. note:: In a live project you would probably use separate server(s) for static files and hence our live.ini files does not configure a public directory
248
The ``resource`` directory
249
^^^^^^^^^^^^^^^^^^^^^^^^^^
251
The resource directory contains our root resource. This is the first file that
252
will handle any requests.
257
Finally, our wsgiapp.py can be used to wire up any other wsgi applications,
258
such as cookies, authentication, etc.
263
Just a quick aside as it might come in handy. You can start your example project right now by using the command::
265
$ paster serve development.ini
267
Which should return the following::
269
$ paster serve development.ini
270
Starting server in PID 22237.
271
serving on http://127.0.0.1:8080
276
Next we'll talk about how to build resources and use templating...