.. _qtut_json:

========================================
14: AJAX Development With JSON Renderers
========================================

Modern web apps are more than rendered HTML. Dynamic pages now use JavaScript
to update the UI in the browser by requesting server data as JSON. Pyramid
supports this with a *JSON renderer*.


Background
==========

As we saw in :doc:`templating`, view declarations can specify a renderer.
Output from the view is then run through the renderer, which generates and
returns the response. We first used a Chameleon renderer, then a Jinja2
renderer.

Renderers aren't limited, however, to templates that generate HTML. Pyramid
supplies a JSON renderer which takes Python data, serializes it to JSON, and
performs some other functions such as setting the content type. In fact you can
write your own renderer (or extend a built-in renderer) containing custom logic
for your unique application.


Steps
=====

#. First we copy the results of the ``view_classes`` step:

   .. code-block:: bash

       cd ..; cp -r view_classes json; cd json
       $VENV/bin/pip install -e .

#. We add a new route for ``hello_json`` in ``json/tutorial/__init__.py``:

   .. literalinclude:: json/tutorial/__init__.py
       :linenos:

#. Rather than implement a new view, we will "stack" another decorator on the
   ``hello`` view in ``views.py``:

   .. literalinclude:: json/tutorial/views.py
       :linenos:

#. We need a new functional test at the end of ``json/tutorial/tests.py``:

   .. literalinclude:: json/tutorial/tests.py
       :linenos:

#. Run the tests:

   .. code-block:: bash

       $VENV/bin/pytest tutorial/tests.py -q
       .....
       5 passed in 0.47 seconds


#. Run your Pyramid application with:

   .. code-block:: bash

    $ $VENV/bin/pserve development.ini --reload

#. Open http://localhost:6543/howdy.json in your browser and you will see the
   resulting JSON response.


Analysis
========

Earlier we changed our view functions and methods to return Python data. This
change to a data-oriented view layer made test writing easier, decoupling the
templating from the view logic.

Since Pyramid has a JSON renderer as well as the templating renderers, it is an
easy step to return JSON. In this case we kept the exact same view and arranged
to return a JSON encoding of the view data. We did this by:

- Adding a route to map ``/howdy.json`` to a route name.

- Providing a ``@view_config`` that associated that route name with an existing
  view.

- *Overriding* the view defaults in the view config that mentions the
  ``hello_json`` route, so that when the route is matched, we use the JSON
  renderer rather than the ``home.pt`` template renderer that would otherwise 
  be used.

In fact, for pure AJAX-style web applications, we could re-use the existing
route by using Pyramid's view predicates to match on the ``Accepts:`` header
sent by modern AJAX implementations.

Pyramid's JSON renderer uses the base Python JSON encoder, thus inheriting its
strengths and weaknesses. For example, Python can't natively JSON encode
DateTime objects. There are a number of solutions for this in Pyramid,
including extending the JSON renderer with a custom renderer.

.. seealso:: :ref:`views_which_use_a_renderer`,
   :ref:`json_renderer`, and
   :ref:`adding_and_overriding_renderers`
