Improve documentation for @expose('json').

This commit is contained in:
Ryan Petrello 2016-04-19 07:54:52 -04:00
parent 1a0a72f0b1
commit b41300b5a7
4 changed files with 80 additions and 13 deletions

View File

@ -77,27 +77,51 @@ Exposing Controllers
You tell Pecan which methods in a class are publically-visible via
:func:`~pecan.decorators.expose`. If a method is *not* decorated with
:func:`~pecan.decorators.expose`, Pecan will never route a request to it.
:func:`~pecan.decorators.expose` accepts three optional parameters, some of
which can impact routing and the content type of the response body.
:func:`~pecan.decorators.expose` can be used in a variety of ways. The
simplest case involves passing no arguments. In this scenario, the controller
returns a string representing the HTML response body.
::
from pecan import expose
class RootController(object):
@expose(
template = None,
content_type = 'text/html',
generic = False
)
@expose()
def hello(self):
return 'Hello World'
Let's look at an example using ``template`` and ``content_type``:
A more common use case is to :ref:`specify a template and a namespace
<templates>`::
from pecan import expose
class RootController(object):
@expose('html_template.mako')
def hello(self):
return {'msg': 'Hello!'}
::
<!-- html_template.mako -->
<html>
<body>${msg}</body>
</html>
Pecan also has built-in support for a special :ref:`JSON renderer
<expose_json>`, which translates template namespaces into rendered JSON text::
from pecan import expose
class RootController(object):
@expose('json')
def hello(self):
return {'msg': 'Hello!'}
:func:`~pecan.decorators.expose` calls can also be stacked, which allows you to
serialize content differently depending on how the content is requested::
from pecan import expose
class RootController(object):
@ -115,14 +139,15 @@ different arguments.
@expose('json')
The first tells Pecan to serialize the response namespace using JSON
serialization when the client requests ``/hello.json``.
serialization when the client requests ``/hello.json`` or if an
``Accept: application/json`` header is present.
::
@expose('text_template.mako', content_type='text/plain')
The second tells Pecan to use the ``text_template.mako`` template file when the
client requests ``/hello.txt``.
client requests ``/hello.txt`` or asks for text/plain via an ``Accept`` header.
::
@ -130,7 +155,8 @@ client requests ``/hello.txt``.
The third tells Pecan to use the ``html_template.mako`` template file when the
client requests ``/hello.html``. If the client requests ``/hello``, Pecan will
use the ``text/html`` content type by default.
use the ``text/html`` content type by default; in the absense of an explicit
content type, Pecan assumes the client wants HTML.
.. seealso::

View File

@ -95,6 +95,7 @@ template, and :func:`~pecan.core.render` returns the rendered output as text.
def controller(self):
return render('my_template.html', dict(message='I am the namespace'))
.. _expose_json:
The JSON Renderer
-----------------
@ -141,3 +142,11 @@ your application's configuration::
},
# ...
}
...and specify the renderer in the :func:`~pecan.decorators.expose` method::
class RootController(object):
@expose('my_renderer:template.html')
def index(self):
return dict(name='Bob')

View File

@ -32,7 +32,9 @@ def expose(template=None,
access via HTTP, and to configure that access.
:param template: The path to a template, relative to the base template
directory.
directory. Can also be passed a string representing
a special or custom renderer, such as ``'json'`` for
:ref:`expose_json`.
:param content_type: The content-type to use for this template.
:param generic: A boolean which flags this as a "generic" controller,
which uses generic functions based upon

View File

@ -20,7 +20,7 @@ from pecan import (
abort, make_app, override_template, render, route
)
from pecan.templating import (
_builtin_renderers as builtin_renderers, error_formatters
_builtin_renderers as builtin_renderers, error_formatters, MakoRenderer
)
from pecan.decorators import accept_noncanonical
from pecan.tests import PecanTestCase
@ -1920,6 +1920,36 @@ class TestEngines(PecanTestCase):
result = dict(loads(r.body.decode()))
assert result == expected_result
def test_custom_renderer(self):
class RootController(object):
@expose('backwards:mako.html')
def index(self, name='Joe'):
return dict(name=name)
class BackwardsRenderer(MakoRenderer):
# Custom renderer that reverses all string namespace values
def render(self, template_path, namespace):
namespace = dict(
(k, v[::-1])
for k, v in namespace.items()
)
return super(BackwardsRenderer, self).render(template_path,
namespace)
app = TestApp(Pecan(
RootController(),
template_path=self.template_path,
custom_renderers={'backwards': BackwardsRenderer}
))
r = app.get('/')
assert r.status_int == 200
assert b_("<h1>Hello, eoJ!</h1>") in r.body
r = app.get('/index.html?name=Tim')
assert r.status_int == 200
assert b_("<h1>Hello, miT!</h1>") in r.body
def test_override_template(self):
class RootController(object):
@expose('foo.html')