Repository: DataDog/datadogpy

Issue:
api.Monitor.search() returns "400 malformed request" html
Any call to _api.Monitor.search()_ with parameters or without returns a 400 status code as response. For this call the request body is an empty JSON object('{}') rather than being _None_ (as for other 'GET' requests) and the headers accordingly contain _'Content-Type': 'application/json'_

Discussion:

Patch:
diff --git a/datadog/api/resources.py b/datadog/api/resources.py
index ad53a50..23b3663 100644
--- a/datadog/api/resources.py
+++ b/datadog/api/resources.py
@@ -373,7 +373,9 @@ class ActionAPIResource(object):
                 resource_id=id,
                 action_name=name
             )
-
+        if method == "GET":
+            # Do not add body to GET requests, it causes 400 Bad request responses on EU site
+            body = None
         return APIClient.submit(method, path, api_version, body, **params)
 
     @classmethod
@@ -403,4 +405,7 @@ class ActionAPIResource(object):
             action_name=name,
             resource_id=id
         )
+        if method == "GET":
+            # Do not add body to GET requests, it causes 400 Bad request responses on EU site
+            body = None
         return APIClient.submit(method, path, api_version, body)


Test patch:
diff --git a/tests/unit/api/helper.py b/tests/unit/api/helper.py
index 4ba6cc4..c72ee09 100644
--- a/tests/unit/api/helper.py
+++ b/tests/unit/api/helper.py
@@ -143,8 +143,8 @@ class DatadogAPITestCase(unittest.TestCase):
 
     def request_called_with(self, method, url, data=None, params=None):
         (req_method, req_url), others = self.request_mock.call_args()
-        self.assertEquals(method, req_method, req_method)
-        self.assertEquals(url, req_url, req_url)
+        self.assertEqual(method, req_method, req_method)
+        self.assertEqual(url, req_url, req_url)
 
         if data:
             self.assertIn('data', others)
@@ -155,7 +155,7 @@ class DatadogAPITestCase(unittest.TestCase):
             self.assertIn('params', others)
             for (k, v) in iteritems(params):
                 self.assertIn(k, others['params'], others['params'])
-                self.assertEquals(v, others['params'][k])
+                self.assertEqual(v, others['params'][k])
 
     def assertIn(self, first, second, msg=None):
         msg = msg or "{0} not in {1}".format(first, second)
diff --git a/tests/unit/api/test_api.py b/tests/unit/api/test_api.py
index 3fc99a8..2ba1698 100644
--- a/tests/unit/api/test_api.py
+++ b/tests/unit/api/test_api.py
@@ -173,7 +173,7 @@ class TestInitialization(DatadogAPINoInitialization):
             self.assertEquals(getattr(api, attr_name), expected_value)
 
         @preserve_environ_datadog
-        def test_api_params_from_params(env_name, parameter, attr_name, value ):
+        def test_api_params_from_params(env_name, parameter, attr_name, value):
             """
             Unset env_name environment variable
             Initialize API with parameter=value
@@ -221,6 +221,8 @@ class TestResources(DatadogAPIWithInitialization):
         MyGetable.get(getable_object_id, otherparam="val")
         self.request_called_with('GET', "host/api/v1/getables/" + str(getable_object_id),
                                  params={'otherparam': "val"})
+        _, kwargs = self.request_mock.call_args()
+        self.assertIsNone(kwargs["data"])
 
     def test_listable(self):
         """
@@ -228,6 +230,8 @@ class TestResources(DatadogAPIWithInitialization):
         """
         MyListable.get_all(otherparam="val")
         self.request_called_with('GET', "host/api/v1/listables", params={'otherparam': "val"})
+        _, kwargs = self.request_mock.call_args()
+        self.assertIsNone(kwargs["data"])
 
     def test_updatable(self):
         """
@@ -258,6 +262,8 @@ class TestResources(DatadogAPIWithInitialization):
             'host/api/v1/resource_name/{0}/sub_resource_name'.format(resource_id),
             params={'otherparam': "val"}
         )
+        _, kwargs = self.request_mock.call_args()
+        self.assertIsNone(kwargs["data"])
 
     def test_addable_sub_resources(self):
         """
@@ -341,9 +347,10 @@ class TestResources(DatadogAPIWithInitialization):
         self.request_called_with(
             'GET',
             'host/api/v1/actionables/{0}/actionname'.format(str(actionable_object_id)),
-            params={'param1': 'val1', 'param2': 'val2'},
-            data={}
+            params={'param1': 'val1', 'param2': 'val2'}
         )
+        _, kwargs = self.request_mock.call_args()
+        self.assertIsNone(kwargs["data"])
 
         MyActionable.trigger_action(
             'POST',
@@ -357,6 +364,18 @@ class TestResources(DatadogAPIWithInitialization):
             data={'mydata': "val"}
         )
 
+        MyActionable.trigger_action(
+            'GET',
+            'actionname',
+            id=actionable_object_id,
+        )
+        self.request_called_with(
+            'GET',
+            'host/api/v1/actionname/{0}'.format(actionable_object_id)
+        )
+        _, kwargs = self.request_mock.call_args()
+        self.assertIsNone(kwargs["data"])
+
 
 class TestMetricResource(DatadogAPIWithInitialization):
 
@@ -476,6 +495,7 @@ class TestMetricResource(DatadogAPIWithInitialization):
             serie = dict(metric='metric.numerical', points=point)
             self.submit_and_assess_metric_payload(serie)
 
+
 class TestServiceCheckResource(DatadogAPIWithInitialization):
 
     def test_service_check_supports_none_parameters(self):