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 milla.dispatch import routing
|
||||||
from . import gallery, thumbnails
|
from . import (
|
||||||
import os
|
base,
|
||||||
|
gallery,
|
||||||
|
thumbnails,
|
||||||
|
)
|
||||||
|
import functools
|
||||||
import milla.util
|
import milla.util
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_CONFIG = {
|
DEFAULT_CONFIG = {
|
||||||
|
@ -30,3 +35,21 @@ class Application(milla.Application):
|
||||||
|
|
||||||
r.add_route('/', gallery.GalleryController())
|
r.add_route('/', gallery.GalleryController())
|
||||||
r.add_route('/thumbnails/{image}', thumbnails.ThumbnailController())
|
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