Difference Between Data and JSON Parameters in Python Requests Package

Difference between data and json parameters in python requests package

To answer my own question, it appears my two examples above do the same thing and that using the json parameter does indeed set the content-type in the headers to application/json. In my first example above using the data parameter, the content-type in the headers would need to be set manually.

What is the difference between the `data` and `json` named arguments with requests.post?

Passing a dict to data causes the dict to be form-encoded, as though you were submitting a form on an HTML page; e.g., data={"example": "request"} will be sent in the request body as example=request. The json keyword, on the other hand, encodes its argument as a JSON value instead (and also sets the Content-Type header to application/json).

Difference between data and params in Python requests?

params form the query string in the URL, data is used to fill the body of a request (together with files). GET and HEAD requests have no body.

For the majority of servers accepting a POST request, the data is expected to be passed in as the request body.

You need to consult the documentation for the specific API you are calling as to what they expect, but if you have to assume, assume you have to use data.

what is the difference between data and params in requests?

According to the requests documentation:

  • A requests.post(url, data=data) will make an HTTP POST request, and
  • A requests.get(url, params=params) will make an HTTP GET request

To understand the difference between the two, see this answer.

Here's how params can be used in a GET:

payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.get('http://httpbin.org/get', params=payload)
print(r.text)

Which outputs

{
"args": {
"key1": "value1",
"key2": "value2"
},
[...]
"url": "http://httpbin.org/get?key1=value1&key2=value2"
}

Notice that the payload ended up in the query string of the URL. Since they ended up there, they are viewable by anyone who has access to the URL, which is why you shouldn't use query strings for sensitive data like passwords.

Here's how data can be used in a POST:

payload = 'foobar'
r = requests.post('http://httpbin.org/post', data=payload)
print(r.text)

Which outputs

{
"args": {},
"data": "foobar",
[...]
"url": "http://httpbin.org/post"
}

Notice how the POST data does not show up in the query strings, as they are transmitted through the body of the request instead.


Critique of this answer has pointed out that there are more options. I never denied such a thing in my original answer, but let's take a closer look.

The documentation examples always show:

  • The params keyword used for GET, and
  • The data keyword used for POST

But that doesn't mean they are mutually exclusive.

In theory you could mix the two together in a POST:

data = 'foobar'
params = {'key1': 'value1', 'key2': 'value2'}
r = requests.post('http://httpbin.org/post', params=params, data=data)
print(r.text)

Which outputs

{
"args": {
"key1": "value1",
"key2": "value2"
},
"data": "foobar",
[...]
"url": "http://httpbin.org/post?key1=value1&key2=value2"
}

But you cannot mix data into a GET:

data = 'foobar'
params = {'key1': 'value1', 'key2': 'value2'}
r = requests.get('http://httpbin.org/get', params=params, data=data)
print(r.text)

Outputs:

{
"args": {
"key1": "value1",
"key2": "value2"
},
[...]
"url": "http://httpbin.org/get?key1=value1&key2=value2"
}

Notice how the data field is gone.

HTTP requests and JSON parsing in Python

I recommend using the awesome requests library:

import requests

url = 'http://maps.googleapis.com/maps/api/directions/json'

params = dict(
origin='Chicago,IL',
destination='Los+Angeles,CA',
waypoints='Joplin,MO|Oklahoma+City,OK',
sensor='false'
)

resp = requests.get(url=url, params=params)
data = resp.json() # Check the JSON Response Content documentation below

JSON Response Content: https://requests.readthedocs.io/en/master/user/quickstart/#json-response-content

What is the difference between those two requests?

There is no "native dict" format in HTTP world.

The real difference is that requests is too smart.

When using data= in requests, you are trying to post multipart/form-data. In this case, a dict will be unzipped into key-value pairs in form-data format.

When using json= in requests, requests will automatically json.dumps your dict into a raw byte string and set Content-Type for you.

But in urllib, it does nothing more than you give. You need to manually json.dumps your dict. So I believe the example you give is wrong. it should be like the following:

import urllib2
import json

req = urllib2.Request(url)
req.add_header('Content-Type', 'application/json')
resp = urllib2.urlopen(req, json.dumps(body)) #body from above
print resp.read()

Thanks for @t.m.adam's reminding.

How to POST JSON data with Python Requests?

Starting with Requests version 2.4.2, you can use the json= parameter (which takes a dictionary) instead of data= (which takes a string) in the call:

>>> import requests
>>> r = requests.post('http://httpbin.org/post', json={"key": "value"})
>>> r.status_code
200
>>> r.json()
{'args': {},
'data': '{"key": "value"}',
'files': {},
'form': {},
'headers': {'Accept': '*/*',
'Accept-Encoding': 'gzip, deflate',
'Connection': 'close',
'Content-Length': '16',
'Content-Type': 'application/json',
'Host': 'httpbin.org',
'User-Agent': 'python-requests/2.4.3 CPython/3.4.0',
'X-Request-Id': 'xx-xx-xx'},
'json': {'key': 'value'},
'origin': 'x.x.x.x',
'url': 'http://httpbin.org/post'}

JSON formatting for API requests, lines only needed if value is given in Python

Leave those fields out initially, then add them in an if statement if needed.

test = {
"name": hostname,
"device_type": type,
"device_role": role,
"tenant": tenant,
"platform": platform,
"serial": chassis_serial,
"site": site,
"location": location,
"rack": rack,
"face": face,
"status": status,
"custom_fields": {}
}

if position:
test['position'] = position
if ilo:
test['custom_fields']['management_ip_address'] = str(ilo)


Related Topics



Leave a reply



Submit