4

Q. Is it possible to send json data with GET request?

I want to pass some filter parameters to read results from DB

params = {'is_coming_soon': False, 'is_paid': True, 'limit': 100, 'skip': 0}
headers = {'content-type': 'application/json'}
response = requests.get(url=url, headers=headers, params=params)

In server side I am receiving all values as string,

how can I make request to get proper boolean values not string one.

OmPrakash
  • 198
  • 1
  • 9

3 Answers3

5

To send a json payload use the data or json argument instead of params. Convert the dict to json first using json.dumps, and double-check the conversion if you like:

import json

payload = json.dumps(params)
print(payload)  # '{"is_coming_soon": false, "is_paid": true, "limit": 100, "skip": 0}'

response = requests.get(url=url, headers=headers, data=payload)

Also, you can debug requests calls like this:

import requests
import logging

from http.client import HTTPConnection
# from httplib import HTTPConnection  # Python 2

HTTPConnection.debuglevel = 1

logging.basicConfig() 
logging.getLogger().setLevel(logging.DEBUG)
requests_log = logging.getLogger("requests.packages.urllib3")
requests_log.setLevel(logging.DEBUG)
requests_log.propagate = True

response = requests.get(url=url, headers=headers, data=payload)
brennan
  • 3,392
  • 24
  • 42
  • Thanks @brennan, this works, now I just need to update server side request parsing mechanism. – OmPrakash Sep 21 '17 at 06:58
  • 1
    Correction: Requests (both `get` and `post` calls) handles both keyword arguments data and json. Only when using `json=` is the Python object JSON-serialised. If you use `data=` you need to take care of that yourself. – CodeMantle May 18 '20 at 15:59
4

requests has a helper kwarg json that does exactly this.

You should be able to write

params = {'is_coming_soon': False, 'is_paid': True, 'limit': 100, 'skip': 0}
headers = {'content-type': 'application/json'}
response = requests.get(url=url, headers=headers, params=params)

as

data = {'is_coming_soon': False, 'is_paid': True, 'limit': 100, 'skip': 0}
response = requests.get(url, json=data)

instead.

Cireo
  • 4,197
  • 1
  • 19
  • 24
2

Summary:

There is no built-in option to use the params parameter and have bool values converted from python True|False to json true|false.

We must manually process the bool values to turn them into lowercase strings. Several methods for processing are presented below.

ex: encode the individual values with 'true' if x else 'false' or json.dumps(x)

Why

The internal methods of requests.request use stringification to convert any non-string value. See prepare_url in PreparedRequest.

If query and params are both used, then enc_params are converted to string by '%s&%s' % (query, enc_params). If not, then the query=enc_params is string encoded inside requote_url.

### excerpt from PreparedRequest.prepare_url

        enc_params = self._encode_params(params)
        if enc_params:
            if query:
                query = '%s&%s' % (query, enc_params)
            else:
                query = enc_params

        url = requote_uri(urlunparse([scheme, netloc, path, None, query, fragment]))
        self.url = url
str(True)         # 'True'
str(False)        # 'False'
'%s' % True       # 'True

import json
json_dumps(None)  # 'null'   <-- probably want to avoid null for Boolean values
json.dumps(True)  # 'true'   <-- lowercase
json.dumps(False) # 'false'  <-- lowercase

How

For one or two values you could use a simple ternary, but this gets verbose quickly.

is_coming_soon, is_paid = False, True
params = {'is_coming_soon': 'true' if is_coming_soon else 'false',
          'is_paid': 'true' if is_paid else 'false',
          'limit': 100, 'skip': 0}

or maybe a quick function to do it for you:

encode_bool = lambda x: 'true' if x else 'false'
is_coming_soon, is_paid = False, True
params = {'is_coming_soon': encode_bool(is_coming_soon),
          'is_paid': encode_bool(is_paid),
          'limit': 100, 'skip': 0}

Or we could move up the stack and make a function to modify all the Booleans

# Caveat: this only encodes one level of structure.
def encode_boolean_values(kv):
  """ convert bool values to 'true'/'false' strings for json compat """
  enc = lambda x : x if not isinstance(x, bool) else 'true' if x else 'false'
  {k: enc(v) for k,v in kv.items()}

is_coming_soon, is_paid = False, True
params = {'is_coming_soon': is_coming_soon,
          'is_paid': is_paid,
          'limit': 100, 'skip': 0}
params = encode_boolean_values(params)

Note: you could use json.dumps() instead of the ternary. I use the ternary to collapse Null in with False rather than making it 'null'

Community
  • 1
  • 1
spazm
  • 4,399
  • 31
  • 30