Browse Source

feat(api): generalize text/plain exception rendering

If response.data['detail'] can be accessed, it is returned directly.

Otherwise, the data structure is more complex.  This commit stringifies
all values regardless of potential nesting using JSON serialization/
deserialization, so that we obtain a list/dict/... that contains scalar
values only (no ErrorDetail objects etc.)  This structure can then be
transformed into human-readable YAML form.
Peter Thomassen 4 years ago
parent
commit
8bffb16d9e
2 changed files with 7 additions and 21 deletions
  1. 6 21
      api/desecapi/renderers.py
  2. 1 0
      api/requirements.txt

+ 6 - 21
api/desecapi/renderers.py

@@ -1,3 +1,6 @@
+import json
+import yaml
+
 from rest_framework import renderers
 
 
@@ -12,28 +15,10 @@ class PlainTextRenderer(renderers.BaseRenderer):
 
         if response and response.exception:
             response['Content-Type'] = 'text/plain'
-
             try:
                 return data['detail']
-            except (KeyError, TypeError):
-                pass
-
-            try:
-                details = list(filter(None, [el.get('detail') for el in data]))
-                if details:
-                    return ', '.join(details)
-            except (TypeError, AttributeError):
-                pass
-
-            try:
-                return '; '.join([f'{err.code}: {err}' for err in data])
-            except (TypeError, AttributeError):
-                pass
-
-            raise ValueError('Expected response.data to be one of the following:\n'
-                             '- a dict with error details in response.data[\'detail\'],\n'
-                             '- a list with at least one element that has error details in element[\'detail\'];\n'
-                             '- a list with all elements being ErrorDetail instances;\n'
-                             'but got %s:\n\n%s' % (type(response.data), response.data))
+            except:
+                data = json.loads(json.dumps(data))  # stringify exception objects in potentially nested data structure
+                return yaml.safe_dump(data, default_flow_style=False)
 
         return data

+ 1 - 0
api/requirements.txt

@@ -14,5 +14,6 @@ psycopg2~=2.8.5
 prometheus-client~=0.9.0  # added to control django-prometheus' dependency version
 psl-dns~=1.0
 pylibmc~=1.6.1
+pyyaml~=5.3.1
 requests~=2.25.0
 uwsgi~=2.0.0