5

Trying to use urllib3 to post JSON-encoded data. Just want my POST payload to be raw JSON string, with content type application/json. I just cannot see how to do this.

The urllib3 documentation describes posting data in "fields", i.e. dicts with (key,value) pairs, like how HTML forms are URL-encoded with the URL. But I don't want to do that.

The closest I've been able to get is this (I just guessed where to put the data, as it's not documented anywhere that I can find):

http = urllib3.PoolManager()
headers = urllib3.util.make_headers(basic_auth=key+":")
r = http.request_encode_body('POST', path, json.dumps(payload), headers=headers)

which causes this urllib3 error:

File "C:\Python27\lib\site-packages\urllib3-1.7.1-py2.7.egg\urllib3\filepost.py", line 44, in iter_field_objects
yield RequestField.from_tuples(*field)
TypeError: from_tuples() takes exactly 3 arguments (2 given)

Thanks for any pointers!

user2855982
  • 51
  • 1
  • 1
  • 2
  • 1
    Use the requests module for Python.. –  Oct 07 '13 at 19:38
  • 4
    @user2799617: the requests module provides a convenient, but very narrow interface *over* `urllib3`, for some tasks, like asynchronous programming, using requests is not practical, but using the more explicit interface exposed by urllib3 is quite workable. in any case, `urllib3` is much more convenient than any of the built in python libraries, (httplib or urllib/urllib2). – SingleNegationElimination Oct 07 '13 at 20:55

1 Answers1

6

you can't use PoolManager.request for that, it tries to concoct the body iself, use the lower level urlopen:

In [16]: pool = urllib3.PoolManager()

In [17]: print pool.urlopen('POST', 'http://httpbin.org/post', headers={'Content-Type':'application/json'}, body='{"sup":"son"}').data
{
  "data": "{\"sup\":\"son\"}",
  "form": {},
  "json": {
    "sup": "son"
  },
  "origin": "50.74.23.243",
  "args": {},
  "url": "http://httpbin.org/post",
  "files": {},
  "headers": {
    "Host": "httpbin.org",
    "Content-Length": "13",
    "Content-Type": "application/json",
    "Accept-Encoding": "identity",
    "Connection": "close"
  }
}
SingleNegationElimination
  • 151,563
  • 33
  • 264
  • 304
  • 1
    ^- This is correct. The [RequestMethods.request_encode_body(...)](http://urllib3.readthedocs.org/en/latest/helpers.html#urllib3.request.RequestMethods.request_encode_body) is a little too high-level for op, as it will attempt to encode the field dict-like parameter for you. The lower-level `pool.urlopen(..., body=payload)` is exactly what op wants. Reading the docs now, I can see it's not obvious that this is what's going on. A pull request with improved docs would be lovely. :) – shazow Oct 07 '13 at 21:03