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
from cubicweb import (
ValidationError,
)
from cubicweb.web import (
RequestError as _CWRequestError,
)
from .. import (
CREATION_ROLE,
)
......@@ -368,6 +371,27 @@ def validation_failed(exc, request):
return json_problem(status=422, **kwargs)
@json_config(
route_name='cubicweb-jsonschema.entities',
context=_CWRequestError,
# This view should be usable for unauthenticated users.
permission=None,
)
def cubicweb_requesterror(exc, request):
"""Handler for CubicWeb's RequestError instances.
It will return a RFC 7807 formatted error response from exception found in
context.
This view breaks backward-compatibility with CubicWeb's behaviour without
cubicweb-jsonschema as the JSON response returned by CubicWeb is not
application/problem+json.
"""
if request.cw_cnx is not None:
request.cw_cnx.rollback()
return json_problem(status=int(exc.status), detail=exc.reason)
@json_config(
route_name='cubicweb-jsonschema.entities',
context=Exception,
......
......@@ -22,6 +22,7 @@ from unittest import skip
import jsonschema
from mock import patch
import six
from webob.multidict import MultiDict
from cubicweb import Binary, ValidationError
......@@ -440,6 +441,29 @@ class EntitiesTC(BaseTC):
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):
self.login()
# 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
else:
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__':
import unittest
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