From be03d894a3a0626ede5a90e492291013a4ced857 Mon Sep 17 00:00:00 2001
From: Erwan Rouchet <rouchet@teklia.com>
Date: Tue, 17 Dec 2019 16:10:07 +0100
Subject: [PATCH] Add x-name on request bodies in manage.py generateschema
 instead of patch.py

---
 arkindex/project/openapi.py            | 11 +++++
 arkindex/project/tests/test_openapi.py | 59 ++++++++++++++++++++++++++
 openapi/patch.py                       | 16 -------
 openapi/patch.yml                      |  1 -
 4 files changed, 70 insertions(+), 17 deletions(-)

diff --git a/arkindex/project/openapi.py b/arkindex/project/openapi.py
index 3814855ad2..3087dac568 100644
--- a/arkindex/project/openapi.py
+++ b/arkindex/project/openapi.py
@@ -68,6 +68,17 @@ class AutoSchema(BaseAutoSchema):
             }
         return schema
 
+    def _get_request_body(self, path, method):
+        """
+        Add x-name to requestBody objects to allow APIStar to use `body={}` arguments on requests
+        """
+        request_body = super()._get_request_body(path, method)
+        if not request_body:
+            return request_body
+        assert 'x-name' not in request_body
+        request_body['x-name'] = 'body'
+        return request_body
+
     def get_operation(self, path, method):
         operation = super().get_operation(path, method)
 
diff --git a/arkindex/project/tests/test_openapi.py b/arkindex/project/tests/test_openapi.py
index 3d0d9a3bc4..ec40e33515 100644
--- a/arkindex/project/tests/test_openapi.py
+++ b/arkindex/project/tests/test_openapi.py
@@ -282,3 +282,62 @@ class TestOpenAPI(TestCase):
             },
             'required': ['my_field'],
         })
+
+    def test_request_body_apistar_compat(self):
+        """
+        Test x-name is added to requestBody to allow APIStar to use the request body as `body={}`
+        """
+
+        class ThingSerializer(serializers.Serializer):
+            my_field = serializers.CharField()
+
+        class ThingView(APIView):
+            serializer_class = ThingSerializer
+
+            def get_serializer(self):
+                return self.serializer_class()
+
+            def post(self, *args, **kwargs):
+                pass
+
+        inspector = AutoSchema()
+        inspector.view = create_view(ThingView, 'POST', create_request('/test/'))
+        self.assertDictEqual(
+            inspector.get_operation('/test/', 'POST'),
+            {
+                'operationId': 'CreateThing',
+                'parameters': [],
+                'requestBody': {
+                    'content': {
+                        'application/json': {
+                            'schema': {
+                                'properties': {
+                                    'my_field': {
+                                        'type': 'string',
+                                    },
+                                },
+                                'required': ['my_field']
+                            },
+                        },
+                    },
+                    'x-name': 'body',
+                },
+                'responses': {
+                    '200': {
+                        'content': {
+                            'application/json': {
+                                'schema': {
+                                    'properties': {
+                                        'my_field': {
+                                            'type': 'string',
+                                        },
+                                    },
+                                    'required': ['my_field']
+                                },
+                            },
+                        },
+                        'description': '',
+                    }
+                },
+            }
+        )
diff --git a/openapi/patch.py b/openapi/patch.py
index 20e131da9e..f823465625 100755
--- a/openapi/patch.py
+++ b/openapi/patch.py
@@ -86,22 +86,6 @@ def update_schema(schema, patches):
     schema.setdefault('info', {})
     schema['info']['version'] = ark_version
 
-    # Add x-name property on request body objects to let apistar register the parameters
-    for path, methods in schema['paths'].items():
-        for method, operation in methods.items():
-            if 'requestBody' not in operation:
-                continue
-            if not operation['requestBody']['content'].get('application/json', {}).get('schema'):
-                # Ignore empty schemas
-                continue
-
-            # Make sure we do not duplicate an existing parameter name
-            assert not any(param['name'] == 'body' for param in operation['parameters']), \
-                'Operation already has a body parameter'
-
-            print('Adding x-name to {} on {}'.format(method, path), file=sys.stderr)
-            operation['requestBody']['x-name'] = 'body'
-
     return schema
 
 
diff --git a/openapi/patch.yml b/openapi/patch.yml
index 60086011ba..6a2645d5f1 100644
--- a/openapi/patch.yml
+++ b/openapi/patch.yml
@@ -251,7 +251,6 @@ paths:
                   type: array
               required:
               - ids
-        x-name: body
       tags:
       - elements
   /api/v1/element/{child}/parent/{parent}/:
-- 
GitLab