app: Support multiple resource representations
The `VariedResponse` class essentially turns the website into a REST API. When a controller returns a response object that is an instance of this class, the response representation sent to the user-agent will vary based on the value of the `Accept` request header. Specifically, requests containing `Accept: application/json` will receive a JSON-encoded object, while typical browser requests will get an (X)HTML document.master
parent
bb9f19ff04
commit
860c36b0f2
|
@ -1,7 +1,12 @@
|
|||
from milla.dispatch import routing
|
||||
from . import gallery, thumbnails
|
||||
import os
|
||||
from . import (
|
||||
base,
|
||||
gallery,
|
||||
thumbnails,
|
||||
)
|
||||
import functools
|
||||
import milla.util
|
||||
import os
|
||||
|
||||
|
||||
DEFAULT_CONFIG = {
|
||||
|
@ -30,3 +35,21 @@ class Application(milla.Application):
|
|||
|
||||
r.add_route('/', gallery.GalleryController())
|
||||
r.add_route('/thumbnails/{image}', thumbnails.ThumbnailController())
|
||||
|
||||
def make_request(self, environ):
|
||||
request = super(Application, self).make_request(environ)
|
||||
default_format = base.VariedResponse.default_content_type
|
||||
offers = [
|
||||
'application/json',
|
||||
'application/xhtml+xml',
|
||||
'text/html',
|
||||
]
|
||||
want_fmt = request.accept.best_match(offers, default_format)
|
||||
if want_fmt == 'application/json':
|
||||
request.want = 'json'
|
||||
elif want_fmt == 'text/html':
|
||||
request.want = 'html'
|
||||
else:
|
||||
request.want = 'xhtml'
|
||||
request.ResponseClass = functools.partial(base.VariedResponse, request)
|
||||
return request
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
import jinja2
|
||||
import json
|
||||
import milla
|
||||
|
||||
|
||||
class Template(object):
|
||||
|
||||
LOADER = jinja2.PackageLoader(__name__.rsplit('.', 1)[0])
|
||||
|
||||
def __init__(self, name):
|
||||
self.env = jinja2.Environment(loader=self.LOADER)
|
||||
self.tmpl = self.env.get_template(name)
|
||||
|
||||
def render(self, context):
|
||||
return self.tmpl.render(**context)
|
||||
|
||||
|
||||
class VariedResponse(milla.Response):
|
||||
|
||||
def __init__(self, request, *args, **kwargs):
|
||||
super(VariedResponse, self).__init__(*args, **kwargs)
|
||||
self.request = request
|
||||
|
||||
def set_payload(self, template, context=None):
|
||||
if not self.vary:
|
||||
self.vary = ['Accept']
|
||||
elif 'accept' not in (v.lower() for v in self.vary):
|
||||
self.vary = self.vary + ('Accept',)
|
||||
if context is None:
|
||||
context = {}
|
||||
if template is None or self.request.want == 'json':
|
||||
self.content_type = str('application/json')
|
||||
json.dump(context, self.body_file)
|
||||
else:
|
||||
if self.request.want == 'xhtml':
|
||||
self.content_type = str('application/xhtml+xml')
|
||||
self.render(template, context)
|
||||
|
||||
def render(self, template, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
t = Template(template)
|
||||
t.env.globals.update(
|
||||
url=self.request.create_href,
|
||||
static=self.request.static_resource,
|
||||
)
|
||||
if hasattr(self.request, 'user'):
|
||||
t.env.globals['user'] = self.request.user
|
||||
self.text = t.render(context)
|
Loading…
Reference in New Issue