diff --git a/README.md b/README.md index a2d4e40..efaa932 100644 --- a/README.md +++ b/README.md @@ -257,6 +257,7 @@ DEBUG = True settings.configure( RENDER=not DEBUG, + NO_THROW=not DEBUG, RENDER_URL='http://127.0.0.1:9009/render', ) ``` diff --git a/react/conf.py b/react/conf.py index fe0a98d..69d5777 100644 --- a/react/conf.py +++ b/react/conf.py @@ -1,6 +1,7 @@ class Conf(object): _render_url = 'http://127.0.0.1:9009/render' _render = True + _no_throw = False # Indicates that we should rely on Django's settings as the # canonical reference and use the above defaults as fallbacks. @@ -32,10 +33,24 @@ def RENDER(self): return self._render - def configure(self, RENDER_URL=None, RENDER=None): + @property + def NO_THROW(self): + if not self._PROXY_DJANGO_SETTINGS: + return self._no_throw + + from django.conf import settings + + if hasattr(settings, 'REACT'): + return settings.REACT.get('NO_THROW', self._no_throw) + + return self._no_throw + + def configure(self, RENDER_URL=None, RENDER=None, NO_THROW=None): if RENDER_URL is not None: self._render_url = RENDER_URL if RENDER is not None: self._render = RENDER + if NO_THROW is not None: + self._no_throw = NO_THROW settings = Conf() diff --git a/react/render_server.py b/react/render_server.py index b7d7d48..6c3df52 100644 --- a/react/render_server.py +++ b/react/render_server.py @@ -60,12 +60,18 @@ def render(self, path, props=None, to_static_markup=False, request_headers=None, timeout=timeout ) except requests.ConnectionError: - raise RenderServerError('Could not connect to render server at {}'.format(url)) + if conf.settings.NO_THROW: + return RenderedComponent('', serialized_props, {}) + else: + raise RenderServerError('Could not connect to render server at {}'.format(url)) if res.status_code != 200: - raise RenderServerError( - 'Unexpected response from render server at {} - {}: {}'.format(url, res.status_code, res.text) - ) + if conf.settings.NO_THROW: + return RenderedComponent('', serialized_props, {}) + else: + raise RenderServerError( + 'Unexpected response from render server at {} - {}: {}'.format(url, res.status_code, res.text) + ) obj = res.json() @@ -73,16 +79,20 @@ def render(self, path, props=None, to_static_markup=False, request_headers=None, err = obj.pop('error', None) data = obj - if err: + if markup is None: + if conf.settings.NO_THROW: + return RenderedComponent('', serialized_props, {}) + else: + raise ReactRenderingError('Render server failed to return markup. Returned: {}'.format(obj)) + + if err and not conf.settings.NO_THROW: if 'message' in err and 'stack' in err: raise ReactRenderingError( 'Message: {}\n\nStack trace: {}'.format(err['message'], err['stack']) ) raise ReactRenderingError(err) - if markup is None: - raise ReactRenderingError('Render server failed to return markup. Returned: {}'.format(obj)) - + return RenderedComponent(markup, serialized_props, data) diff --git a/tests/test_rendering.py b/tests/test_rendering.py index c6ed898..cf6f260 100644 --- a/tests/test_rendering.py +++ b/tests/test_rendering.py @@ -106,6 +106,30 @@ def test_render_setting_is_respected(self): self.assertEqual(str(rendered), '') self.assertEqual(rendered.props, '{"name": "world!"}') + @mock.patch('requests.post') + def test_no_throw_setting_is_respected(self, requests_post_mock): + mock_settings = Conf() + mock_settings.configure(NO_THROW=True) + mock_json = { + 'markup': '', + 'error': { + 'type': 'Error', + 'message': 'Error message', + }, + } + response_mock = mock.Mock() + response_mock.status_code = 500 + response_mock.text = json.dumps(mock_json) + response_mock.json = mock.Mock(return_value=mock_json) + requests_post_mock.return_value = response_mock + with mock.patch('react.conf.settings', mock_settings): + rendered = render_component( + Components.HELLO_WORLD_JSX, + {'name': 'world!'}, + to_static_markup=True, + ) + self.assertEqual(rendered.markup, '') + @mock.patch('requests.post') def test_can_pass_additional_request_headers(self, requests_post_mock): mock_json = {