How do I pass raw POST data into urllib3?
Asked Answered
A

1

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!

Anechoic answered 7/10, 2013 at 19:29 Comment(2)
Use the requests module for Python..Holytide
@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).Gerianne
G
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"
  }
}
Gerianne answered 7/10, 2013 at 20:52 Comment(1)
^- This is correct. The 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. :)Everson

© 2022 - 2024 — McMap. All rights reserved.