Add JsonErrorMixin:

This commit adds the JsonErrorMixin for formatting error message from a
given RequestHandler as JSON.
This commit is contained in:
AWeberChrisMcGuire 2014-11-14 15:27:13 -05:00
parent 8a6b82c83c
commit ca9e0b535b
4 changed files with 130 additions and 11 deletions

View file

@ -24,12 +24,30 @@ Requirements
Example Example
------- -------
This examples demonstrates how to use ``sprockets.mixins.json_error`` by ... This examples demonstrates how to use ``sprockets.mixins.json_error`` to format
errors as JSON.
.. code:: python .. code:: python
from sprockets import mixins.json_error from sprockets import mixins.json_error
from tornado import web
class MyRequestHandler(statsd.RequestMetricsMixin,
web.RequestHandler):
def get(self, *args, **kwargs):
raise web.HTTPError(404, log_message='My reason')
The response from the handler will automatically be formatted as:
.. code:: json
{
"message": "My reason",
"type": "Not Found"
}
# Example here
Version History Version History
--------------- ---------------
@ -48,4 +66,4 @@ Available at https://sprocketsmixinsjson_error.readthedocs.org/en/latest/history
:target: https://pypi.python.org/pypi/sprockets.mixins.json_error :target: https://pypi.python.org/pypi/sprockets.mixins.json_error
.. |License| image:: https://pypip.in/license/sprockets.mixins.json_error/badge.svg? .. |License| image:: https://pypip.in/license/sprockets.mixins.json_error/badge.svg?
:target: https://sprocketsmixinsjson_error.readthedocs.org :target: https://sprocketsmixinsjson_error.readthedocs.org

View file

@ -4,5 +4,42 @@ mixins.json_error
Handler mixin for writing JSON errors Handler mixin for writing JSON errors
""" """
version_info = (0, 0, 0) version_info = (1, 0, 0)
__version__ = '.'.join(str(v) for v in version_info) __version__ = '.'.join(str(v) for v in version_info)
class JsonErrorMixin(object):
def write_error(self, status_code, **kwargs):
"""Suppress the automatic rendering of HTML code upon an error.
:param int status_code:
The HTTP status code the :class:`HTTPError` raised.
:param dict kwargs:
Automatically filled with exception information including
the error that was raised, the class of error raised, and an
object.
"""
if kwargs.get('error'):
raised_error = kwargs.get('error')
else:
_, raised_error, _ = kwargs['exc_info']
error_message = getattr(
raised_error, 'log_message', 'Unexpected Error')
error_type = getattr(raised_error, 'error_type', self._reason)
self.error = {
'message': error_message,
'type': error_type,
}
if hasattr(raised_error, 'documentation_url'):
self.error['documentation_url'] = raised_error.documentation_url
error_status_code = getattr(raised_error, 'status_code', status_code)
self.set_status(error_status_code)
self.set_header('Content-Type', 'application/json; charset=UTF-8')
self.finish(self.error)

View file

@ -1,3 +1,4 @@
coverage>=3.7,<4 coverage>=3.7,<4
coveralls>=0.4,<1 coveralls>=0.4,<1
nose>=1.3,<2 nose>=1.3,<2
tornado>=4.0,<5

View file

@ -2,12 +2,75 @@
Tests for the sprockets.mixins.json_error package Tests for the sprockets.mixins.json_error package
""" """
import mock import json
try:
import unittest2 as unittest from sprockets.mixins import json_error
except ImportError: from tornado import testing, web
import unittest
class MyTest(unittest.TestCase): class HTTPErrorRequestHandler(
pass json_error.JsonErrorMixin, web.RequestHandler):
def get(self):
raise web.HTTPError(400, 'Error Reason')
class CustomExceptionRequestHandler(
json_error.JsonErrorMixin, web.RequestHandler):
class FailureError(Exception):
status_code = 400
log_message = 'Too much Foo'
error_type = 'FailureError'
documentation_url = 'http://www.example.com'
def get(self):
raise self.FailureError()
class UnexpectedErrorRequestHandler(
json_error.JsonErrorMixin, web.RequestHandler):
def get(self):
raise Exception()
class TestHTTPError(testing.AsyncHTTPTestCase):
def get_app(self):
return web.Application([('/', HTTPErrorRequestHandler)])
def test_tornado_thrown_exception(self):
response = self.fetch('/')
expected = {'message': 'Error Reason', 'type': 'Bad Request'}
self.assertEqual(json.loads(response.body), expected)
class TestCustomExceptions(testing.AsyncHTTPTestCase):
def get_app(self):
return web.Application([('/', CustomExceptionRequestHandler)])
def test_tornado_custom_exception(self):
response = self.fetch('/')
expected = {
'message': 'Too much Foo',
'type': 'FailureError',
'documentation_url': 'http://www.example.com',
}
self.assertEqual(json.loads(response.body), expected)
class TestUnexpectedError(testing.AsyncHTTPTestCase):
def get_app(self):
return web.Application([('/', UnexpectedErrorRequestHandler)])
def test_unexpected_exception(self):
response = self.fetch('/')
expected = {
'message': 'Unexpected Error',
'type': 'Internal Server Error'
}
self.assertEqual(json.loads(response.body), expected)