~canonical-ci-engineering/ubuntu-ci-services-itself/restish

« back to all changes in this revision

Viewing changes to docs-build/introduction.rst

  • Committer: Evan Dandrea
  • Date: 2014-02-28 23:57:35 UTC
  • Revision ID: evan.dandrea@canonical.com-20140228235735-r3qoc6u6eqclhbqb
Initial commit.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
**************************
 
2
An Introduction to Restish
 
3
**************************
 
4
 
 
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
 
8
or database engine.
 
9
 
 
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>`_.
 
14
 
 
15
 
 
16
Why Restish?
 
17
============
 
18
 
 
19
Background
 
20
----------
 
21
 
 
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.
 
27
 
 
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.
 
32
 
 
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. 
 
39
 
 
40
Advantages & Disadvantages
 
41
--------------------------
 
42
 
 
43
The advantages that restish has are 
 
44
 
 
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
 
48
 
 
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)
 
53
 
 
54
Executive Summary for Coders
 
55
----------------------------
 
56
 
 
57
.. code-block:: python
 
58
 
 
59
    # implicit resource locator
 
60
    @resource.child()
 
61
    def blog(self, request, segments):
 
62
        return BlogResource()
 
63
 
 
64
    # explicit resource locator
 
65
    @resource.child('blog')
 
66
    def whatever(self, request, segments):
 
67
        return BlogResource()
 
68
 
 
69
    # templated resource locator
 
70
    @resource.child('blog/{entry}')
 
71
    def whatever(self, request, segments, entry=None):
 
72
        return BlogEntry(entry)
 
73
 
 
74
    # templated resource locator with partial match
 
75
    @resource.child('blog/entry-{id}')
 
76
    def whatever(self, request, segments, id=None):
 
77
        return BlogEntry(id)
 
78
 
 
79
    # accept anything and return a 200 OK with content
 
80
    @resource.GET()
 
81
    def html(self, request):
 
82
        return http.ok([('Content-Type','text/html')], '<p>Hello Wolrd</p>' )
 
83
 
 
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"}' )
 
88
 
 
89
    # short cut for accept code
 
90
    @resource.GET(accept='json')
 
91
    def json(self, request):
 
92
        return http.ok( [], simplejson.dumps({'foo': 'bar'}) )
 
93
 
 
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 )
 
99
 
 
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'}
 
105
 
 
106
    # accept anything and use url module to build a redirect
 
107
    @resource.GET()
 
108
    def html(self, request):
 
109
        current_url = request.url.path_qs
 
110
        return http.see_other( current_url.child('othersegment') )
 
111
 
 
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) )
 
117
 
 
118
 
 
119
How to start a restish project
 
120
==============================
 
121
 
 
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
 
123
 
 
124
Using paster create
 
125
-------------------
 
126
 
 
127
First you use paste with a 'restish' template:: 
 
128
 
 
129
  $ paster create --template=restish
 
130
 
 
131
This will create a basic, minimal restish project::
 
132
 
 
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 
 
137
    Variables:
 
138
      egg:      myproject
 
139
      package:  myproject
 
140
      project:  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
 
146
        Recursing into lib
 
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
 
166
 
 
167
 
 
168
What is in the template project
 
169
-------------------------------
 
170
 
 
171
The files in this project are as follows::
 
172
 
 
173
    .
 
174
    |-- development.ini
 
175
    |-- live.ini
 
176
    |-- myproject
 
177
    |   |-- __init__.py
 
178
    |   |-- lib
 
179
    |   |   |-- __init__.py
 
180
    |   |   |-- guard.py
 
181
    |   |   `-- templating.py
 
182
    |   |-- public
 
183
    |   |   `-- index.html
 
184
    |   |-- resource
 
185
    |   |   |-- __init__.py
 
186
    |   |   `-- root.py
 
187
    |   `-- wsgiapp.py
 
188
    |-- myproject.egg-info
 
189
    |   |-- PKG-INFO
 
190
    |   |-- SOURCES.txt
 
191
    |   |-- dependency_links.txt
 
192
    |   |-- entry_points.txt
 
193
    |   |-- not-zip-safe
 
194
    |   |-- paster_plugins.txt
 
195
    |   |-- requires.txt
 
196
    |   `-- top_level.txt
 
197
    |-- myproject.ini
 
198
    `-- setup.py
 
199
 
 
200
We'll simplify that a bit by removing __init__'s and packaging files..::
 
201
 
 
202
    .
 
203
    |-- myproject.ini
 
204
    |-- development.ini
 
205
    |-- live.ini
 
206
    |
 
207
    |-- myproject
 
208
    |   |-- lib
 
209
    |   |   |-- guard.py
 
210
    |   |   `-- templating.py
 
211
    |   |-- public
 
212
    |   |   `-- index.html
 
213
    |   |-- resource
 
214
    |   |   `-- root.py
 
215
    |   `-- wsgiapp.py
 
216
 
 
217
The ini files
 
218
^^^^^^^^^^^^^
 
219
 
 
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
 
223
serve the project. 
 
224
 
 
225
The ``lib`` directory
 
226
^^^^^^^^^^^^^^^^^^^^^
 
227
 
 
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.
 
231
 
 
232
We tend to put most of our project library code in here.
 
233
 
 
234
The ``public`` directory
 
235
^^^^^^^^^^^^^^^^^^^^^^^^
 
236
 
 
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
 
239
the file is for.
 
240
 
 
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.
 
245
 
 
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
 
247
 
 
248
The ``resource`` directory
 
249
^^^^^^^^^^^^^^^^^^^^^^^^^^
 
250
 
 
251
The resource directory contains our root resource. This is the first file that
 
252
will handle any requests.
 
253
 
 
254
The WSGI setup
 
255
^^^^^^^^^^^^^^
 
256
 
 
257
Finally, our wsgiapp.py can be used to wire up any other wsgi applications,
 
258
such as cookies, authentication, etc.
 
259
 
 
260
Starting a server
 
261
-----------------
 
262
 
 
263
Just a quick aside as it might come in handy. You can start your example project right now by using the command::
 
264
 
 
265
  $ paster serve development.ini
 
266
 
 
267
Which should return the following::
 
268
 
 
269
  $ paster serve development.ini
 
270
  Starting server in PID 22237.
 
271
  serving on http://127.0.0.1:8080
 
272
 
 
273
Next Steps..
 
274
------------
 
275
 
 
276
Next we'll talk about how to build resources and use templating...
 
277