Steve Piercy
2018-04-12 a794d04bbdad962c944340a10a14a574babe1c7c
commit | author | age
bf76ad 1 .. index::
c5f24b 2    single: Bicking, Ian
590fe7 3    single: WebOb
bf76ad 4
d5b2f4 5 .. _webob_chapter:
CM 6
888d65 7 Request and Response Objects
CM 8 ============================
bf76ad 9
CM 10 .. note:: This chapter is adapted from a portion of the :term:`WebOb`
11    documentation, originally written by Ian Bicking.
888d65 12
d868ff 13 :app:`Pyramid` uses the :term:`WebOb` package as a basis for its
888d65 14 :term:`request` and :term:`response` object implementations.  The
d868ff 15 :term:`request` object that is passed to a :app:`Pyramid` :term:`view` is an
e0d42d 16 instance of the :class:`pyramid.request.Request` class, which is a subclass of
SP 17 :class:`webob.Request`.  The :term:`response` returned from a :app:`Pyramid`
18 :term:`view` :term:`renderer` is an instance of the
d868ff 19 :mod:`pyramid.response.Response` class, which is a subclass of the
CM 20 :class:`webob.Response` class.  Users can also return an instance of
21 :class:`pyramid.response.Response` directly from a view as necessary.
888d65 22
e0d42d 23 WebOb is a project separate from :app:`Pyramid` with a separate set of authors
SP 24 and a fully separate `set of documentation
25 <http://docs.webob.org/en/latest/index.html>`_.  :app:`Pyramid` adds some
e005c2 26 functionality to the standard WebOb request, which is documented in the
MM 27 :ref:`request_module` API documentation.
888d65 28
d868ff 29 WebOb provides objects for HTTP requests and responses.  Specifically it does
7b1612 30 this by wrapping the `WSGI <https://wsgi.readthedocs.io/en/latest/>`_ request
1cb30e 31 environment and response status, header list, and app_iter (body) values.
888d65 32
d868ff 33 WebOb request and response objects provide many conveniences for parsing WSGI
CM 34 requests and forming WSGI responses.  WebOb is a nice way to represent "raw"
e0d42d 35 WSGI requests and responses.  However, we won't cover that use case in this
d868ff 36 document, as users of :app:`Pyramid` don't typically need to use the
CM 37 WSGI-related features of WebOb directly.  The `reference documentation
e005c2 38 <http://docs.webob.org/en/latest/reference.html>`_ shows many examples of
844e98 39 creating requests and using response objects in this manner, however.
888d65 40
8c56ae 41 .. index::
CM 42    single: request object
c5f24b 43    single: request attributes
8c56ae 44
888d65 45 Request
CM 46 ~~~~~~~
47
48 The request object is a wrapper around the `WSGI environ dictionary
1cb30e 49 <https://www.python.org/dev/peps/pep-0333/#environ-variables>`_.  This
e0d42d 50 dictionary contains keys for each header, keys that describe the request
SP 51 (including the path and query string), a file-like object for the request body,
52 and a variety of custom keys.  You can always access the environ with
53 ``req.environ``.
888d65 54
e0d42d 55 Some of the most important and interesting attributes of a request object are
SP 56 below.
888d65 57
e0d42d 58 ``req.method``
SP 59     The request method, e.g., ``GET``, ``POST``
888d65 60
e0d42d 61 ``req.GET``
SP 62     A :term:`multidict` with all the variables in the query string.
888d65 63
e0d42d 64 ``req.POST``
SP 65     A :term:`multidict` with all the variables in the request body.  This only
66     has variables if the request was a ``POST`` and it is a form submission.
888d65 67
e0d42d 68 ``req.params``
SP 69     A :term:`multidict` with a combination of everything in ``req.GET`` and
70     ``req.POST``.
888d65 71
e0d42d 72 ``req.body``
SP 73     The contents of the body of the request.  This contains the entire request
74     body as a string.  This is useful when the request is a ``POST`` that is
75     *not* a form submission, or a request like a ``PUT``.  You can also get
76     ``req.body_file`` for a file-like object.
888d65 77
6a0602 78 ``req.json_body``
CM 79     The JSON-decoded contents of the body of the request. See
80     :ref:`request_json_body`.
81
e0d42d 82 ``req.cookies``
888d65 83     A simple dictionary of all the cookies.
CM 84
e0d42d 85 ``req.headers``
31309f 86     A dictionary of all the headers.  This dictionary is case-insensitive.
888d65 87
e0d42d 88 ``req.urlvars`` and ``req.urlargs``
SP 89     ``req.urlvars`` are the keyword parameters associated with the request URL.
90     ``req.urlargs`` are the positional parameters. These are set by products
7b1612 91     like `Routes <https://routes.readthedocs.io/en/latest/>`_ and `Selector
e0d42d 92     <https://github.com/lukearno/selector>`_.
888d65 93
e0d42d 94 Also for standard HTTP request headers, there are usually attributes such as
SP 95 ``req.accept_language``, ``req.content_length``, and ``req.user_agent``.  These
96 properties expose the *parsed* form of each header, for whatever parsing makes
97 sense.  For instance, ``req.if_modified_since`` returns a :mod:`datetime`
98 object (or None if the header is was not provided).
888d65 99
e0d42d 100 .. note:: Full API documentation for the :app:`Pyramid` request object is
SP 101    available in :ref:`request_module`.
5c7bdc 102
bf76ad 103 .. index::
c5f24b 104    single: request attributes (special)
590fe7 105
41cc8f 106 .. _special_request_attributes:
CM 107
fd5ae9 108 Special Attributes Added to the Request by :app:`Pyramid`
e0d42d 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
590fe7 110
72ad33 111 In addition to the standard :term:`WebOb` attributes, :app:`Pyramid` adds
CM 112 special attributes to every request: ``context``, ``registry``, ``root``,
113 ``subpath``, ``traversed``, ``view_name``, ``virtual_root``,
e0d42d 114 ``virtual_root_path``, ``session``, ``matchdict``, and ``matched_route``. These
SP 115 attributes are documented further within the :class:`pyramid.request.Request`
116 API documentation.
590fe7 117
CM 118 .. index::
c5f24b 119    single: request URLs
bf76ad 120
888d65 121 URLs
CM 122 ++++
123
e0d42d 124 In addition to these attributes, there are several ways to get the URL of the
SP 125 request and its parts.  We'll show various values for an example URL
16388c 126 ``http://localhost/app/blog?id=10``, where the application is mounted at
44f1df 127 ``http://localhost/app``.
888d65 128
e0d42d 129 ``req.url``
SP 130     The full request URL with query string, e.g.,
16388c 131     ``http://localhost/app/blog?id=10``
BB 132
e0d42d 133 ``req.host``
SP 134     The host information in the URL, e.g., ``localhost``
16388c 135
e0d42d 136 ``req.host_url``
16388c 137     The URL with the host, e.g., ``http://localhost``
888d65 138
e0d42d 139 ``req.application_url``
SP 140     The URL of the application (just the ``SCRIPT_NAME`` portion of the path,
141     not ``PATH_INFO``), e.g., ``http://localhost/app``
888d65 142
e0d42d 143 ``req.path_url``
SP 144     The URL of the application including the ``PATH_INFO``, e.g.,
16388c 145     ``http://localhost/app/blog``
BB 146
e0d42d 147 ``req.path``
SP 148     The URL including ``PATH_INFO`` without the host or scheme, e.g.,
16388c 149     ``/app/blog``
BB 150
e0d42d 151 ``req.path_qs``
SP 152     The URL including ``PATH_INFO`` and the query string, e.g,
16388c 153     ``/app/blog?id=10``
BB 154
e0d42d 155 ``req.query_string``
SP 156     The query string in the URL, e.g., ``id=10``
888d65 157
e0d42d 158 ``req.relative_url(url, to_application=False)``
SP 159     Gives a URL relative to the current URL.  If ``to_application`` is True,
160     then resolves it relative to ``req.application_url``.
bf76ad 161
CM 162 .. index::
c5f24b 163    single: request methods
bf76ad 164
888d65 165 Methods
CM 166 +++++++
167
d868ff 168 There are methods of request objects documented in
CM 169 :class:`pyramid.request.Request` but you'll find that you won't use very many
170 of them.  Here are a couple that might be useful:
888d65 171
e0d42d 172 ``Request.blank(base_url)``
SP 173     Creates a new request with blank information, based at the given URL.  This
174     can be useful for subrequests and artificial requests.  You can also use
175     ``req.copy()`` to copy an existing request, or for subrequests
176     ``req.copy_get()`` which copies the request but always turns it into a GET
177     (which is safer to share for subrequests).
888d65 178
e0d42d 179 ``req.get_response(wsgi_application)``
SP 180     This method calls the given WSGI application with this request, and returns
181     a :class:`pyramid.response.Response` object.  You can also use this for
182     subrequests or testing.
bf76ad 183
CM 184 .. index::
844726 185    single: request (and text/unicode)
CM 186    single: unicode and text (and the request)
888d65 187
844726 188 Text (Unicode)
CM 189 ++++++++++++++
888d65 190
844726 191 Many of the properties of the request object will be text values (``unicode``
CM 192 under Python 2 or ``str`` under Python 3) if the request encoding/charset is
193 provided.  If it is provided, the values in ``req.POST``, ``req.GET``,
194 ``req.params``, and ``req.cookies`` will contain text.  The client *can*
888d65 195 indicate the charset with something like ``Content-Type:
844726 196 application/x-www-form-urlencoded; charset=utf8``, but browsers seldom set
CM 197 this.  You can reset the charset of an existing request with ``newreq =
198 req.decode('utf-8')``, or during instantiation with ``Request(environ,
199 charset='utf8')``.
888d65 200
2a1c3f 201 .. index::
CM 202    single: multidict (WebOb)
203
204 .. _multidict_narr:
205
206 Multidict
207 +++++++++
208
e0d42d 209 Several attributes of a WebOb request are multidict structures (such as
2a1c3f 210 ``request.GET``, ``request.POST``, and ``request.params``).  A multidict is a
e0d42d 211 dictionary where a key can have multiple values.  The quintessential example is
SP 212 a query string like ``?pref=red&pref=blue``; the ``pref`` variable has two
2a1c3f 213 values: ``red`` and ``blue``.
CM 214
e0d42d 215 In a multidict, when you do ``request.GET['pref']``, you'll get back only
SP 216 ``"blue"`` (the last value of ``pref``).  This returned result might not be
217 expected—sometimes returning a string, and sometimes returning a list—and may
218 be cause of frequent exceptions.  If you want *all* the values back, use
219 ``request.GET.getall('pref')``.  If you want to be sure there is *one and only
220 one* value, use ``request.GET.getone('pref')``, which will raise an exception
221 if there is zero or more than one value for ``pref``.
2a1c3f 222
e0d42d 223 When you use operations like ``request.GET.items()``, you'll get back something
SP 224 like ``[('pref', 'red'), ('pref', 'blue')]``.  All the key/value pairs will
225 show up.  Similarly ``request.GET.keys()`` returns ``['pref', 'pref']``. 
226 Multidict is a view on a list of tuples; all the keys are ordered, and all the
227 values are ordered.
2a1c3f 228
CM 229 API documentation for a multidict exists as
230 :class:`pyramid.interfaces.IMultiDict`.
231
6ce1e0 232 .. index::
CM 233    pair: json_body; request
234
6a0602 235 .. _request_json_body:
CM 236
e0d42d 237 Dealing with a JSON-Encoded Request Body
6a0602 238 ++++++++++++++++++++++++++++++++++++++++
CM 239
40dbf4 240 .. versionadded:: 1.1
6a0602 241
CM 242 :attr:`pyramid.request.Request.json_body` is a property that returns a
e0d42d 243 :term:`JSON`-decoded representation of the request body.  If the request does
SP 244 not have a body, or the body is not a properly JSON-encoded value, an exception
245 will be raised when this attribute is accessed.
6a0602 246
e0d42d 247 This attribute is useful when you invoke a :app:`Pyramid` view callable via,
SP 248 for example, jQuery's ``$.ajax`` function, which has the potential to send a
249 request with a JSON-encoded body.
6a0602 250
CM 251 Using ``request.json_body`` is equivalent to:
252
253 .. code-block:: python
254
255    from json import loads
256    loads(request.body, encoding=request.charset)
257
e0d42d 258 Here's how to construct an AJAX request in JavaScript using :term:`jQuery` that
SP 259 allows you to use the ``request.json_body`` attribute when the request is sent
260 to a :app:`Pyramid` application:
6a0602 261
CM 262 .. code-block:: javascript
263
e0d42d 264     jQuery.ajax({type:'POST',
6a0602 265                  url: 'http://localhost:6543/', // the pyramid server
e0d42d 266                  data: JSON.stringify({'a':1}),
e33496 267                  contentType: 'application/json; charset=utf-8'});
6a0602 268
CM 269 When such a request reaches a view in your application, the
270 ``request.json_body`` attribute will be available in the view callable body.
271
22f221 272 .. code-block:: python
6a0602 273
e33496 274     @view_config(renderer='string')
6a0602 275     def aview(request):
edfc4f 276         print(request.json_body)
e33496 277         return 'OK'
6a0602 278
CM 279 For the above view, printed to the console will be:
280
281 .. code-block:: python
282
283     {u'a': 1}
284
e0d42d 285 For bonus points, here's a bit of client-side code that will produce a request
SP 286 that has a body suitable for reading via ``request.json_body`` using Python's
287 ``urllib2`` instead of a JavaScript AJAX request:
0b0b20 288
CM 289 .. code-block:: python
290
291     import urllib2
e0d42d 292     import json
0b0b20 293
CM 294     json_payload = json.dumps({'a':1})
295     headers = {'Content-Type':'application/json; charset=utf-8'}
296     req = urllib2.Request('http://localhost:6543/', json_payload, headers)
297     resp = urllib2.urlopen(req)
298
2660f5 299 If you are doing Cross-origin resource sharing (CORS), then the standard
CM 300 requires the browser to do a pre-flight HTTP OPTIONS request. The easiest way
e0d42d 301 to handle this is to add an extra ``view_config`` for the same route, with
SP 302 ``request_method`` set to ``OPTIONS``, and set the desired response header
303 before returning. You can find examples of response headers `Access control
304 CORS, Preflighted requests
305 <https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests>`_.
271191 306
b37b97 307 .. index::
CM 308    single: cleaning up after request
309
310 .. _cleaning_up_after_a_request:
311
e0d42d 312 Cleaning up after a Request
b37b97 313 +++++++++++++++++++++++++++
CM 314
e0d42d 315 Sometimes it's required to perform some cleanup at the end of a request when a
SP 316 database connection is involved.
b37b97 317
CM 318 For example, let's say you have a ``mypackage`` :app:`Pyramid` application
319 package that uses SQLAlchemy, and you'd like the current SQLAlchemy database
320 session to be removed after each request.  Put the following in the
321 ``mypackage.__init__`` module:
322
323 .. code-block:: python
324    :linenos:
325
326    from mypackage.models import DBSession
327
328    from pyramid.events import subscriber
329    from pyramid.events import NewRequest
330
331    def cleanup_callback(request):
332        DBSession.remove()
333
334    @subscriber(NewRequest)
335    def add_cleanup_callback(event):
336        event.request.add_finished_callback(cleanup_callback)
337
338 Registering the ``cleanup_callback`` finished callback at the start of a
339 request (by causing the ``add_cleanup_callback`` to receive a
340 :class:`pyramid.events.NewRequest` event at the start of each request) will
e0d42d 341 cause the DBSession to be removed whenever request processing has ended. Note
SP 342 that in the example above, for the :class:`pyramid.events.subscriber` decorator
343 to work, the :meth:`pyramid.config.Configurator.scan` method must be called
344 against your ``mypackage`` package during application initialization.
b37b97 345
e0d42d 346 .. note::
SP 347    This is only an example.  In particular, it is not necessary to cause
af098b 348    ``DBSession.remove`` to be called in an application generated from a
SP 349    :app:`Pyramid` cookiecutter, because these all use the ``pyramid_tm`` package.
e0d42d 350    The cleanup done by ``DBSession.remove`` is unnecessary when ``pyramid_tm``
SP 351    :term:`middleware` is configured into the application.
b37b97 352
844e98 353 More Details
CM 354 ++++++++++++
355
e0d42d 356 More detail about the request object API is available as follows.
844e98 357
e0d42d 358 - :class:`pyramid.request.Request` API documentation
844e98 359
e0d42d 360 - `WebOb documentation <http://docs.webob.org/en/latest/index.html>`_.  All
SP 361   methods and attributes of a ``webob.Request`` documented within the WebOb
362   documentation will work with request objects created by :app:`Pyramid`.
8c56ae 363
94b889 364 .. index::
CM 365    single: response object
366
888d65 367 Response
CM 368 ~~~~~~~~
369
fd5ae9 370 The :app:`Pyramid` response object can be imported as
d868ff 371 :class:`pyramid.response.Response`.  This class is a subclass of the
CM 372 ``webob.Response`` class.  The subclass does not add or change any
e0d42d 373 functionality, so the WebOb Response documentation will be completely relevant
SP 374 for this class as well.
94b889 375
CM 376 A response object has three fundamental parts:
888d65 377
e0d42d 378 ``response.status``
SP 379     The response code plus reason message, like ``200 OK``.  To set the code
380     without a message, use ``status_int``, i.e., ``response.status_int = 200``.
888d65 381
e0d42d 382 ``response.headerlist``
SP 383     A list of all the headers, like ``[('Content-Type', 'text/html')]``.
384     There's a case-insensitive :term:`multidict` in ``response.headers`` that
385     also allows you to access these same headers.
888d65 386
e0d42d 387 ``response.app_iter``
SP 388     An iterable (such as a list or generator) that will produce the content of
389     the response.  This is also accessible as ``response.body`` (a string),
390     ``response.text`` (a unicode object, informed by ``response.charset``), and
391     ``response.body_file`` (a file-like object; writing to it appends to
392     ``app_iter``).
888d65 393
d868ff 394 Everything else in the object typically derives from this underlying state.
CM 395 Here are some highlights:
888d65 396
94b889 397 ``response.content_type``
888d65 398     The content type *not* including the ``charset`` parameter.
e0d42d 399     
94b889 400     Typical use: ``response.content_type = 'text/html'``.
888d65 401
ac16ec 402     Default value: ``response.content_type = 'text/html'``.
W 403
e0d42d 404 ``response.charset``
SP 405     The ``charset`` parameter of the content-type, it also informs encoding in
406     ``response.text``. ``response.content_type_params`` is a dictionary of all
407     the parameters.
888d65 408
c705c5 409 ``response.set_cookie(name, value, max_age=None, path='/', ...)``
e0d42d 410     Set a cookie.  The keyword arguments control the various cookie parameters.
SP 411     The ``max_age`` argument is the length for the cookie to live in seconds
412     (you may also use a timedelta object).  The ``Expires`` key will also be
413     set based on the value of ``max_age``.
888d65 414
c705c5 415 ``response.delete_cookie(name, path='/', domain=None)``
e0d42d 416     Delete a cookie from the client.  This sets ``max_age`` to 0 and the cookie
SP 417     value to ``''``.
888d65 418
e0d42d 419 ``response.cache_expires(seconds=0)``
SP 420     This makes the response cacheable for the given number of seconds, or if
421     ``seconds`` is ``0`` then the response is uncacheable (this also sets the
422     ``Expires`` header).
888d65 423
e0d42d 424 ``response(environ, start_response)``
SP 425     The response object is a WSGI application.  As an application, it acts
426     according to how you create it.  It *can* do conditional responses if you
427     pass ``conditional_response=True`` when instantiating (or set that
428     attribute later).  It can also do HEAD and Range requests.
888d65 429
8c56ae 430 .. index::
c5f24b 431    single: response headers
8c56ae 432
888d65 433 Headers
CM 434 +++++++
435
e0d42d 436 Like the request, most HTTP response headers are available as properties. These
SP 437 are parsed, so you can do things like ``response.last_modified =
438 os.path.getmtime(filename)``.
888d65 439
e0d42d 440 The details are available in the :mod:`webob.response` API documentation.
888d65 441
bf76ad 442 .. index::
c5f24b 443    single: response (creating)
bf76ad 444
888d65 445 Instantiating the Response
CM 446 ++++++++++++++++++++++++++
447
e0d42d 448 Of course most of the time you just want to *make* a response.  Generally any
SP 449 attribute of the response can be passed in as a keyword argument to the class,
450 e.g.:
888d65 451
CM 452 .. code-block:: python
16cd50 453   :linenos:
888d65 454
94b889 455   from pyramid.response import Response
888d65 456   response = Response(body='hello world!', content_type='text/plain')
CM 457
ac16ec 458 The status defaults to ``'200 OK'``.
W 459
e0d42d 460 The value of ``content_type`` defaults to
SP 461 ``webob.response.Response.default_content_type``, which is ``text/html``. You
462 can subclass :class:`pyramid.response.Response` and set
ac16ec 463 ``default_content_type`` to override this behavior.
888d65 464
8c56ae 465 .. index::
6ce1e0 466    single: exception responses
8c56ae 467
94b889 468 Exception Responses
CM 469 +++++++++++++++++++
888d65 470
2e6905 471 To facilitate error responses like ``404 Not Found``, the module
e0d42d 472 :mod:`pyramid.httpexceptions` contains classes for each kind of error response.
SP 473 These include boring but appropriate error bodies.  The exceptions exposed by
474 this module, when used under :app:`Pyramid`, should be imported from the
475 :mod:`pyramid.httpexceptions` module.  This import location contains subclasses
476 and replacements that mirror those in the ``webob.exc`` module.
888d65 477
e0d42d 478 Each class is named ``pyramid.httpexceptions.HTTP*``, where ``*`` is the reason
SP 479 for the error.  For instance, :class:`pyramid.httpexceptions.HTTPNotFound`
480 subclasses :class:`pyramid.response.Response`, so you can manipulate the
481 instances in the same way.  A typical example is:
888d65 482
CM 483 .. code-block:: python
16cd50 484     :linenos:
888d65 485
99edc5 486     from pyramid.httpexceptions import HTTPNotFound
CM 487     from pyramid.httpexceptions import HTTPMovedPermanently
888d65 488
CM 489     response = HTTPNotFound('There is no such resource')
490     # or:
491     response = HTTPMovedPermanently(location=new_url)
492
844e98 493 More Details
CM 494 ++++++++++++
495
94b889 496 More details about the response object API are available in the
e0d42d 497 :mod:`pyramid.response` documentation.  More details about exception responses
SP 498 are in the :mod:`pyramid.httpexceptions` API documentation.  The `WebOb
499 documentation <http://docs.webob.org/en/latest/index.html>`_ is also useful.