Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does HTTP POST request body need to be JSON enconded in Python?

I ran into this issue when playing around with an external API. I was sending my body data as a dictionary straight into the request and was getting 400 errors:

data = {   "someParamRange": {     "to": 1000,      "from": 100   },    "anotherParamRange": {     "to": True,      "from": False   } } 

When I added a json.dumps wrap, it works:

data = json.dumps({   "someParamRange": {     "to": 1000,      "from": 100   },    "anotherParamRange": {     "to": True,      "from": False   } }) 

I don't entirely understand why this is necessary, as dictionaries and JSON objects are syntactically identical. Can someone help me understand what is going on behind the scenes here?

For completeness, here are my headers:

headers = {'API-KEY': 'blerg', 'Accept-Encoding': 'UTF-8', 'Content-Type': 'application/json', 'Accept': '*/*', 'username': 'user', 'password': 'pwd'} 

EDIT:

I didn't mention this earlier but now I feel that it may be relevant. I am using the Python Requests library, and another post seems to suggest that you should never have to encode parameters to a request object: https://stackoverflow.com/a/14804320/1012040

"Regardless of whether GET/POST you never have to encode parameters again, it simply takes a dictionary as an argument and is good to go."

Seems like serialization shouldn't be necessary?

My request object:

response = requests.post(url, data=data, headers=headers) 
like image 800
acpigeon Avatar asked Mar 28 '13 23:03

acpigeon


People also ask

How do you pass JSON data in a POST request in Python?

To post a JSON to the server using Python Requests Library, call the requests. post() method and pass the target URL as the first parameter and the JSON data with the json= parameter. The json= parameter takes a dictionary and automatically converts it to a JSON string.

How do you pass a body in a POST request in Python?

You'll want to adapt the data you send in the body of your request to the specified URL. Syntax: requests. post(url, data={key: value}, json={key: value}, headers={key:value}, args) *(data, json, headers parameters are optional.)

What does request JSON do in Python?

json() – Python requests. response. json() returns a JSON object of the result (if the result was written in JSON format, if not it raises an error). Python requests are generally used to fetch the content from a particular resource URI.

Can I send JSON in POST request?

In Postman, change the method next to the URL to 'POST', and under the 'Body' tab choose the 'raw' radio button and then 'JSON (application/json)' from the drop down. You can now type in the JSON you want to send along with the POST request. If this is successful, you should see the new data in your 'db.


1 Answers

Apparently your API requires JSON-encoded and not form-encoded data. When you pass a dict in as the data parameter, the data is form-encoded. When you pass a string (like the result of json.dumps), the data is not form-encoded.

Consider this quote from the requests documentation:

Typically, you want to send some form-encoded data — much like an HTML form. To do this, simply pass a dictionary to the data argument. Your dictionary of data will automatically be form-encoded when the request is made.

There are many times that you want to send data that is not form-encoded. If you pass in a string instead of a dict, that data will be posted directly.

For example, the GitHub API v3 accepts JSON-Encoded POST/PATCH data:

>>> import json >>> url = 'https://api.github.com/some/endpoint' >>> payload = {'some': 'data'}  >>> r = requests.post(url, data=json.dumps(payload)) 

Refs:

  • http://www.w3.org/TR/html401/interact/forms.html#h-17.13.3.4
  • http://docs.python-requests.org/en/latest/user/quickstart/#more-complicated-post-requests
like image 112
Robᵩ Avatar answered Oct 11 '22 21:10

Robᵩ