Reputation: 103
I am having trouble converting the payload data in the form of nested dictionaries to pass it as a data for the POST request using Python requests module. The form data is as below:
payload = {'request': {
'appkey': "936725A4-7D9A-11E5-81AC-86EC8D89CD5A"},
'formdata':{
'currency':'US',
'dataview':'store_default',
'distinct':'_distance, clientkey',
'geolocs':{
'geoloc':[{
'0':{
'address1':'',
'addressline':'19128, PA',
'city':'Philadelphia',
'country':'US',
'latitude':'40.0532987',
'longitude':'-75.23040379999998',
'postalcode':'19128',
'province':'',
'state':'PA'}}]
},
'google_autocomplete':'true',
'limit':'250',
'nobf':'1',
'searchradius':'15|25|50|100|250|350|450|550|650|750|850|950',
'true':'1',
'where':{'partner_reseller': {'eq':'1'}}}
}
r = requests.post(url,data=simplejson.dumps(payload),headers=header)
result = simplejson.loads(str(r.content))
Can somebody please assist me with structure and can point out the mistake in what I have written. I keep getting the following error:
{'code': 1008,
'response': {'message': 'The submitted XML is not properly formed'}}
I'll appreciate your help a lot. Thank you.
Upvotes: 10
Views: 14935
Reputation: 21
You can use this before any post request.
import json, requests
if header.get('Content-Type') == 'application/x-www-form-urlencoded':
params = {k: (json.dumps(v) if isinstance(v, dict) else v) for k, v in params.items()}
response = requests.post(url=url, headers=header, data=params)
Upvotes: 0
Reputation: 570
Taking inspiration from both the previous answers, another approach that I personally find cleaner is to serialize the body into string and set Content-Type header to application/json
import json, requests
#Other stuff
headers = { "Content-Type": "application/json" }
data = json.dumps(payload)
r = requests.post(url,data=data,headers=headers)
Upvotes: 0
Reputation: 486
I had similar problem, frustrating but I solved it. Python requests do not work with nested json, they expect one layer json. It processes like form(application/x-www-form-urlencoded)
# Wrong
data = {'param1': {'a':[100, 200]},
'param2': 'value2',
'param3': False}
# You have to convert values into string:
data = {'param1': json.dumps({'a':[100, 200]}),
'param2': 'value2',
'param3': json.dumps(False)}
In your case:
import json
params = {
'appkey': "936725A4-7D9A-11E5-81AC-86EC8D89CD5A"},
'formdata':{
'currency':'US',
'dataview':'store_default',
'distinct':'_distance, clientkey',
'geolocs':{
'geoloc':[{
'0':{
'address1':'',
'addressline':'19128, PA',
'city':'Philadelphia',
'country':'US',
'latitude':'40.0532987',
'longitude':'-75.23040379999998',
'postalcode':'19128',
'province':'',
'state':'PA'}}]
},
'google_autocomplete':'true',
'limit':'250',
'nobf':'1',
'searchradius':'15|25|50|100|250|350|450|550|650|750|850|950',
'true':'1',
'where':{'partner_reseller': {'eq':'1'}}}
}
payload = {'request': json.dumps(params) }
r = requests.post(url,data=payload) # important to keep payload as json!!!
result = r.text # or depends what the return is..
Upvotes: 16
Reputation: 13964
My suggestion is to use the JSON parameter and let requests both encode the object to JSON and let requests set the Content-Type header to application/json
.
It's very possible that the web service assumes you're passing it XML, unless you specify that you're passing JSON, via setting the Content-Type to application/json. (It's also possible this web API really wants XML too, the docs for the service would tell you)
requests.post(url,json=payload,headers=header)
Upvotes: 13