diff options
| author | Michael Merickel <michael@merickel.org> | 2018-08-29 02:38:13 -0500 |
|---|---|---|
| committer | Michael Merickel <michael@merickel.org> | 2018-09-03 16:39:54 -0500 |
| commit | ed6ddcb8c7badca425093d85e23791f942dd9a34 (patch) | |
| tree | 1cc840a7aec8d3f5bb815ff9174a156bea9c9c15 | |
| parent | 121f45b82f2722c0d5e5c5a7b768270299793eeb (diff) | |
| download | pyramid-ed6ddcb8c7badca425093d85e23791f942dd9a34.tar.gz pyramid-ed6ddcb8c7badca425093d85e23791f942dd9a34.tar.bz2 pyramid-ed6ddcb8c7badca425093d85e23791f942dd9a34.zip | |
update docs and changelog
| -rw-r--r-- | CHANGES.rst | 13 | ||||
| -rw-r--r-- | docs/narr/viewconfig.rst | 52 | ||||
| -rw-r--r-- | pyramid/config/views.py | 5 |
3 files changed, 50 insertions, 20 deletions
diff --git a/CHANGES.rst b/CHANGES.rst index d0dbbe5c0..d3ffa19fc 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -57,6 +57,12 @@ Features - Add support for Python 3.7. Add testing on Python 3.8 with allowed failures. See https://github.com/Pylons/pyramid/pull/3333 +- Added the ``pyramid.config.Configurator.add_accept_view_order`` directive, + allowing users to specify media type preferences in ambiguous situations + such as when several views match. A default ordering is defined for media + types that prefers human-readable html/text responses over JSON. + See https://github.com/Pylons/pyramid/pull/3326 + Bug Fixes --------- @@ -107,6 +113,13 @@ Backward Incompatibilities of previous ``pyramid.httpexceptions.HTTPFound``. See https://github.com/Pylons/pyramid/pull/3328 +- Accept-handling has undergone work to get rid of undefined behaviors and + runtime exceptions. As part of this effort, it is now a hard error to pass + any media ranges to the ``accept`` predicate on routes and views. + Previously, depending on the version of WebOb, this would error on certain + requests or it would work in undefined ways. + https://github.com/Pylons/pyramid/pull/3326 + Documentation Changes --------------------- diff --git a/docs/narr/viewconfig.rst b/docs/narr/viewconfig.rst index e85338573..2060393bb 100644 --- a/docs/narr/viewconfig.rst +++ b/docs/narr/viewconfig.rst @@ -1035,11 +1035,12 @@ Accept Header Content Negotiation --------------------------------- The ``accept`` argument to :meth:`pyramid.config.Configurator.add_view` can be used to control :term:`view lookup` by dispatching to different views based on the HTTP ``Accept`` request header. -Consider the below example in which there are two views, sharing the same view callable. -Each view specifies uses the accept header to trigger the appropriate response renderer. +Consider the example below in which there are three defined views. +Each view uses the ``Accept`` header to trigger an appropriate response renderer. .. code-block:: python + from pyramid.httpexceptions import HTTPNotAcceptable from pyramid.view import view_config @view_config(accept='application/json', renderer='json') @@ -1049,12 +1050,20 @@ Each view specifies uses the accept header to trigger the appropriate response r 'name': request.GET.get('name', 'bob'), } -Wildcard Accept header -++++++++++++++++++++++ + @view_config() + def myview_unacceptable(request): + raise HTTPNotAcceptable The appropriate view is selected here when the client specifies an unambiguous header such as ``Accept: text/*`` or ``Accept: application/json``. -However, by default, if a client specifies ``Accept: */*``, the ordering is undefined. -This can be fixed by telling :app:`Pyramid` what the preferred relative ordering is between various accept mimetypes by using :meth:`pyramid.config.Configurator.add_accept_view_option`. +Similarly, if the client specifies a media type that no view is registered to handle, such as ``Accept: text/plain``, it will fall through to ``myview_unacceptable`` and raise ``406 Not Acceptable``. +There are a few cases in which the client may specify ambiguous constraints: + +- ``Accept: */*``. +- A missing ``Accept`` header. +- An invalid ``Accept`` header. + +In these cases the preferred view is not clearly defined (see :rfc:`7231#section-5.3.2`) and :app:`Pyramid` will select one randomly. +This can be controlled by telling :app:`Pyramid` what the preferred relative ordering is between various media types by using :meth:`pyramid.config.Configurator.add_accept_view_order`. For example: .. code-block:: python @@ -1063,29 +1072,32 @@ For example: def main(global_config, **settings): config = Configurator(settings=settings) - config.add_accept_view_option('text/html') - config.add_accept_view_option( + config.add_accept_view_order('text/html') + config.add_accept_view_order( 'application/json', weighs_more_than='text/html', ) config.scan() return config.make_wsgi_app() -Missing Accept header -+++++++++++++++++++++ +In this case, the ``application/json`` view should always be selected in cases where it is otherwise ambiguous. -The above example will not match any view if the ``Accept`` header is not specified by the client. -This can be solved by adding a fallback view without an ``accept`` predicate. -For example, below the html response will be returned in all cases unless ``application/json`` is requested specifically. +Default Accept Ordering ++++++++++++++++++++++++ -.. code-block:: python +By default, :app:`Pyramid` defines a very simple priority ordering for views that prefers human-readable responses over JSON: - @view_config(accept='application/json', renderer='json') - @view_config(renderer='templates/hello.jinja2') - def myview(request): - return { - 'name': request.GET.get('name', 'bob'), - } +- ``text/html`` +- ``application/xhtml+xml`` +- ``application/xml`` +- ``text/xml`` +- ``text/plain`` +- ``application/json`` + +API clients tend to be able to specify their desired headers with more control than web browsers, and can specify the correct ``Accept`` value, if necessary. +Therefore, the motivation for this ordering is to optimize for readability. +Media types that are not listed above are ordered randomly during :term:`view lookup` between otherwise-similar views. +The defaults can be overridden using :meth:`pyramid.config.Configurator.add_accept_view_order` as described above. .. _influencing_http_caching: diff --git a/pyramid/config/views.py b/pyramid/config/views.py index 4eab27542..6ea672e4d 100644 --- a/pyramid/config/views.py +++ b/pyramid/config/views.py @@ -1245,6 +1245,7 @@ class ViewsConfiguratorMixin(object): 'application/xhtml+xml', 'application/xml', 'text/xml', + 'text/plain', 'application/json', ): self.add_accept_view_order(accept) @@ -1277,6 +1278,10 @@ class ViewsConfiguratorMixin(object): .. versionadded:: 1.10 """ + value = value.lower() + if '*' in value: + raise ConfigurationError( + '"accept" ordering is done between media types, not ranges') discriminator = ('accept view order', value) intr = self.introspectable( 'accept view order', |
