Search code examples
pythonpython-requestshttp-post

Python POST request with Nested Dictionary values/args


Already looked at here, here and here but still having issues. I have a POST data that looks like this:

{
   "config":{
             "param1": "param1 value",
             "param2": "param2 value",
             "param3": "param3 value"
            },
   "name": "Testing API",
   "url": "https://testingapi.my.own.com",
   "enabled": true
}

I have the following headers:

{
  "Content-Type": "application/json",
  "referer": "https://testingapi.my.own.com",
  "X-CSRFToken": "my token value here"
}

How do format this for the session.post?

I am keep getting the response code of 400 and logs are stating that I am not sending the required params in the post request.

Here is the code:

headers = {"Content-Type": "application/json",
           "referer": "https://testingapi.my.own.com",
           "X-CSRFToken": "my token"
}

request_data = {
   "config":{
             "param1": "param1 value",
             "param2": "param2 value",
             "param3": "param3 value"
            },
   "name": "Testing API",
   "url": "https://testingapi.my.own.com",
   "enabled": "true"
}

#tried the following:
r = session.post(url, data =  request_data, headers=headers)
r = session.post(url, json =  json.dumps(request_data), headers=headers)

Solution

  • When you do data = request_data your nested dictionary is not packaged into the request body as you expect. Try inspecting the body attribute of the request object:

    import requests
    s = requests.Session()
    request_data = {
        "config":{
            "param1": "param1 value",
            "param2": "param2 value",
            "param3": "param3 value"
         },
        "name": "Testing API",
        "url": "https://testingapi.my.own.com",
        "enabled": True
    }
    r = s.post('https://httpbin.org/post/404', data=request_data )
    r.request.body
    

    returns

    'url=https%3A%2F%2Ftestingapi.my.own.com&enabled=True&config=param3&config=param2&config=param1&name=Testing+API'

    And when you json = json.dumps(request_data) you json-dump your data twice, so so the server (after unserializing the data one time) only sees a json string rather than an unserialized dict (see requests docs).

    So you need to either serialize your data before passing it to data

    r = s.post('https://httpbin.org/post/404', data=json.dumps(request_data), )
    

    or as Paul has suggested, use the json parameter and pass your data dict to it:

    r = s.post('https://httpbin.org/post/404', json=request_data)