Repository: ithaka/apiron

Issue:
Allow post and put requests to specify a json payload
**Is your feature request related to a problem? Please describe.**
It's not hard to encode data to JSON before calling an endpoint, but it would be convenient to just pass in the data and let the endpoint jsonify it.

**Describe the solution you'd like**
Ideally the endpoint calls would accept a json parameter indicating that I would like my data json encoded before the request is sent.

**Describe alternatives you've considered**
The only alternative that works right now is converting the data to json beforehand and passing it as a string.


Discussion:

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index da311d1..92a5ea6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ## [Unreleased]
 ### Added
+- Ability to pass dict to `json` keyword argument for raw POST body instead of form-encoded data
 - Ability to use regular keyword arguments when calling an endpoint (instead of `path_kwargs`)
 
 ## [2.4.0] - 2019-04-09
diff --git a/apiron/client.py b/apiron/client.py
index 333e30b..74074ed 100644
--- a/apiron/client.py
+++ b/apiron/client.py
@@ -106,6 +106,7 @@ class ServiceCaller:
         path_kwargs=None,
         params=None,
         data=None,
+        json=None,
         headers=None,
         cookies=None,
         auth=None,
@@ -135,6 +136,7 @@ class ServiceCaller:
             url=cls.build_url(host, path),
             params=merged_params,
             data=data,
+            json=json,
             headers=headers,
             cookies=cookies,
             auth=auth,
@@ -152,6 +154,7 @@ class ServiceCaller:
         session=None,
         params=None,
         data=None,
+        json=None,
         headers=None,
         cookies=None,
         auth=None,
@@ -184,6 +187,10 @@ class ServiceCaller:
             ``POST`` data to send to the endpoint.
             A :class:`dict` will be form-encoded, while a :class:`str` will be sent raw
             (default ``None``)
+        :param dict json:
+            (optional)
+            A JSON-serializable dictionary that will be sent as the ``POST`` body
+            (default ``None``)
         :param dict headers:
             HTTP Headers to send to the endpoint
             (default ``None``)
@@ -228,6 +235,7 @@ class ServiceCaller:
                     path_kwargs=path_kwargs,
                     params=params,
                     data=data,
+                    json=json,
                     headers=headers,
                     cookies=cookies,
                     auth=auth,
@@ -249,6 +257,7 @@ class ServiceCaller:
             path_kwargs=path_kwargs,
             params=params,
             data=data,
+            json=json,
             headers=headers,
             cookies=cookies,
             auth=auth,


Test patch:
diff --git a/tests/test_client.py b/tests/test_client.py
index 3a8741b..88af677 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -45,6 +45,7 @@ class TestClient:
         params = {'baz': 'qux'}
         endpoint.get_merged_params.return_value = params
         data = 'I am a data'
+        json = {'raw': 'data'}
         headers = {'Accept': 'stuff'}
         cookies = {'chocolate-chip': 'yes'}
         auth = mock.Mock()
@@ -61,6 +62,7 @@ class TestClient:
                 endpoint,
                 params=params,
                 data=data,
+                json=json,
                 headers=headers,
                 cookies=cookies,
                 auth=auth,
@@ -74,6 +76,7 @@ class TestClient:
                 cookies=cookies,
                 params=params,
                 data=data,
+                json=json,
                 auth=auth,
             )