Commit 63f936c5 authored by Denis Laxalde's avatar Denis Laxalde
Browse files

Add a dedicated error view for cubicweb's RequestError

This view will be selected upon any exception which is a subclass of
cubicweb.web.RequestError when the request has Accept:application/json.
Previously, the "generic_error" view would have been called, but it
cannot accurately handle CubicWeb's web exceptions (it always returns
500, whereas these web exceptions may have a different status code).

Why are these views selected? This is because the RootResource matches
for any request with this Accept:application/json header. (In fact, we'd
want to use this error view only when the request comes from a
sub-resource of the RootResource; but that's not easy to achieve.)

So this new error view convert a cubicweb.web.RequestError into an
application/problem+json response. This is thus not backward compatible
with what CubicWeb would return.

In added test, we use the "format_date" "ajax" controller (of CubicWeb)
with missing argument which then responds with a RemoteCallFailed (with
a 500 status) that is called by our view.
parent ee7941762504
...@@ -24,6 +24,9 @@ from pyramid.view import view_config ...@@ -24,6 +24,9 @@ from pyramid.view import view_config
from cubicweb import ( from cubicweb import (
ValidationError, ValidationError,
) )
from cubicweb.web import (
RequestError as _CWRequestError,
from .. import ( from .. import (
) )
...@@ -368,6 +371,27 @@ def validation_failed(exc, request): ...@@ -368,6 +371,27 @@ def validation_failed(exc, request):
return json_problem(status=422, **kwargs) return json_problem(status=422, **kwargs)
# This view should be usable for unauthenticated users.
def cubicweb_requesterror(exc, request):
"""Handler for CubicWeb's RequestError instances.
It will return a RFC 7807 formatted error response from exception found in
This view breaks backward-compatibility with CubicWeb's behaviour without
cubicweb-jsonschema as the JSON response returned by CubicWeb is not
if request.cw_cnx is not None:
return json_problem(status=int(exc.status), detail=exc.reason)
@json_config( @json_config(
route_name='cubicweb-jsonschema.entities', route_name='cubicweb-jsonschema.entities',
context=Exception, context=Exception,
...@@ -22,6 +22,7 @@ from unittest import skip ...@@ -22,6 +22,7 @@ from unittest import skip
import jsonschema import jsonschema
from mock import patch from mock import patch
import six
from webob.multidict import MultiDict from webob.multidict import MultiDict
from cubicweb import Binary, ValidationError from cubicweb import Binary, ValidationError
...@@ -440,6 +441,29 @@ class EntitiesTC(BaseTC): ...@@ -440,6 +441,29 @@ class EntitiesTC(BaseTC):
self.assertEqual(errors, expected) self.assertEqual(errors, expected)
class BWCompatTC(BaseTC):
"""Tests with 'cubicweb.bwcompat = true'."""
settings = BaseTC.settings.copy()
settings['cubicweb.bwcompat'] = True
def test_cubicweb_requesterror(self):
# Raises RemoteCallFailed (which has status=500).
response = self.webapp.post_json('/ajax?fname=format_date', status=500,
headers={'Accept': 'application/json'})
self.assertEqual(response.content_type, 'application/problem+json')
if six.PY2:
detail = 'TypeError: format_date() takes exactly 2 arguments (1 given)' # noqa: E501
detail = 'TypeError: format_date() missing 1 required positional argument: \'strdate\'' # noqa: E501
self.assertEqual(response.json_body, {
'status': 500,
'title': 'Internal Server Error',
'detail': detail,
if __name__ == '__main__': if __name__ == '__main__':
import unittest import unittest
unittest.main() unittest.main()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment