Source code for fixie.request_handler
"""A request handler for fixie that expects JSON data and validates it."""
import cerberus
import tornado.web
from tornado.escape import utf8
import fixie.jsonutils as json
[docs]class RequestHandler(tornado.web.RequestHandler):
"""A Tornado request handler that prepare the data by loading a
JSON request and then validating the resultant object against
the cerberus schema defined on the class as the 'schema' attribute.
This class is meant to be subclassed.
"""
@property
def validator(self):
v = getattr(self.__class__, '_validator', None)
if v is None:
v = cerberus.Validator(self.schema)
self.__class__._validator = v
return v
[docs] def prepare(self):
self.response = {}
body = self.request.body
if not body:
return
try:
data = json.decode(body)
except ValueError:
self.send_error(400, message='Unable to parse JSON.')
return
if not self.validator.validate(data):
msg = 'Input to ' + self.__class__.__name__ + ' is not valid: '
msg += str(self.validator.errors)
self.send_error(400, message=msg)
return
self.request.arguments.clear()
self.request.arguments.update(data)
[docs] def set_default_headers(self):
self.set_header('Content-Type', 'application/json')
[docs] def write(self, chunk):
"""Writes the given chunk to the output buffer. This overrides (and almost
completely reimplements) ``tornado.web.RequestHandler.write() so that we
can use the default fixie JSON tools.
"""
if self._finished:
raise RuntimeError("Cannot write() after finish()")
if not isinstance(chunk, (bytes, str, dict)):
message = "write() only accepts bytes, unicode, and dict objects"
if isinstance(chunk, list):
message += ". Lists not accepted for security reasons; see http://www.tornadoweb.org/en/stable/web.html#tornado.web.RequestHandler.write"
raise TypeError(message)
if isinstance(chunk, dict):
chunk = json.encode(chunk) + '\n'
self.set_header("Content-Type", "application/json; charset=UTF-8")
chunk = utf8(chunk)
self._write_buffer.append(chunk)
[docs] def write_error(self, status_code, **kwargs):
if 'message' not in kwargs:
if status_code == 405:
kwargs['message'] = 'Invalid HTTP method.'
else:
kwargs['message'] = 'Unknown error.'
self.response = kwargs
self.write(kwargs)