10
votes

Why doesn't this simple code POST data to my service:

import requests
import json

data = {"data" : "24.3"}
data_json = json.dumps(data)
response = requests.post(url, data=data_json)
print response.text

And my service is developed using WCF like this :

  [OperationContract]
  [WebInvoke(Method = "POST", UriTemplate = "/test", ResponseFormat =    
      WebMessageFormat.Json,RequestFormat=WebMessageFormat.Json)]
  string test(string data );

Note: If is remove the input parameter data everything works fine, what may be the issue.

1
When you say it doesn't work, what exactly do you mean? From the last "Note" it sounds like it's more than just "ignores my data" (because without the data "everything works fine"), but then exactly what does happen? - abarnert
Well I think I found the issue. It is with the {"data" : "24.3"} .. for some reasons I need to enclose that as a string thats when my request is going through.. like this "{data : 24.3}" .. anyone care to explain reasons ? - Suave Nti
Have you tried data = {"data": 24.3} (note: a float, not a string)? I don't know WCF, but here's another interpretation: string test(string data) might mean that your server expects a single string as an input (data_json = '"something"' (note: it is a Python string that contains json text that represents json string)), and it doesn't expect a json object. Strictly speaking "application/json" must represent either a json object (e.g., data_json = '{"a", 1}') or a json array (e.g., data_json = '[1,2,3]') therefore it is incorrect to accept just a string. - jfs

1 Answers

26
votes

You need to set the content type header:

data = {"data" : "24.3"}
data_json = json.dumps(data)
headers = {'Content-type': 'application/json'}

response = requests.post(url, data=data_json, headers=headers)

If I set url to http://httpbin.org/post, that server echos back to me what was posted:

>>> import json
>>> import requests
>>> import pprint
>>> url = 'http://httpbin.org/post'
>>> data = {"data" : "24.3"}
>>> data_json = json.dumps(data)
>>> headers = {'Content-type': 'application/json'}
>>> response = requests.post(url, data=data_json, headers=headers)
>>> pprint.pprint(response.json())
{u'args': {},
 u'data': u'{"data": "24.3"}',
 u'files': {},
 u'form': {},
 u'headers': {u'Accept': u'*/*',
              u'Accept-Encoding': u'gzip, deflate, compress',
              u'Connection': u'keep-alive',
              u'Content-Length': u'16',
              u'Content-Type': u'application/json',
              u'Host': u'httpbin.org',
              u'User-Agent': u'python-requests/1.0.3 CPython/2.6.8 Darwin/11.4.2'},
 u'json': {u'data': u'24.3'},
 u'origin': u'109.247.40.35',
 u'url': u'http://httpbin.org/post'}
>>> pprint.pprint(response.json()['json'])
{u'data': u'24.3'}

If you are using requests version 2.4.2 or newer, you can leave the JSON encoding to the library; it'll automatically set the correct Content-Type header for you too. Pass in the data to be sent as JSON into the json keyword argument:

data = {"data" : "24.3"}
response = requests.post(url, json=data)