Since you're trying to pass in a JSON request, you'll need to encode the body as JSON and pass it in with the body field.

For your example, you want to do something like:

import json
encoded_body = json.dumps({
        "description": "Tenaris",
        "ticker": "TS.BA",
        "industry": "Metalúrgica",
        "currency": "ARS",
    })

http = urllib3.PoolManager()

r = http.request('POST', 'http://localhost:8080/assets',
                 headers={'Content-Type': 'application/json'},
                 body=encoded_body)

print r.read() # Do something with the response?

Edit: My original answer was wrong. Updated it to encode the JSON. Also, related question: How do I pass raw POST data into urllib3?

Answer from shazow on Stack Overflow
🌐
urllib3
urllib3.readthedocs.io › en › stable › reference › urllib3.request.html
urllib3.request() - urllib3 2.7.0 documentation
urllib3.request(method, url, *, body=None, fields=None, headers=None, preload_content=True, decode_content=True, redirect=True, retries=None, timeout=3, json=None)¶
Top answer
1 of 3
46

Since you're trying to pass in a JSON request, you'll need to encode the body as JSON and pass it in with the body field.

For your example, you want to do something like:

import json
encoded_body = json.dumps({
        "description": "Tenaris",
        "ticker": "TS.BA",
        "industry": "Metalúrgica",
        "currency": "ARS",
    })

http = urllib3.PoolManager()

r = http.request('POST', 'http://localhost:8080/assets',
                 headers={'Content-Type': 'application/json'},
                 body=encoded_body)

print r.read() # Do something with the response?

Edit: My original answer was wrong. Updated it to encode the JSON. Also, related question: How do I pass raw POST data into urllib3?

2 of 3
3

I ran into this issue when making a call to Gitlab CI. Since the above did not work for me (gave me some kind of error about not being able to concatenate bytes to a string), and because the arguments I was attempting to pass were nested, I thought I would post what ended up working for me:

API_ENDPOINT = "https://gitlab.com/api/v4/projects/{}/pipeline".format(GITLAB_PROJECT_ID)

API_TOKEN = "SomeToken"

data = {
    "ref": ref,
    "variables": [
        {
            "key": "ENVIRONMENT",
            "value": some_env
        },
        {   "key": "S3BUCKET",
            "value": some_bucket
        },
    ]
}

req_headers = {
    'Content-Type': 'application/json',
    'PRIVATE-TOKEN': API_TOKEN,
}

http = urllib3.PoolManager()

encoded_data = json.dumps(data).encode('utf-8')

r = http.request('POST', API_ENDPOINT,
             headers=req_headers,
             body=encoded_data)

resp_body = r.data.decode('utf-8')
resp_dict = json.loads(r.data.decode('utf-8'))

logger.info('Response Code: {}'.format(r.status))
logger.info('Response Body: {}'.format(resp_body))

if 'message' in resp_body:
    logfile_msg = 'Failed Gitlab Response-- {} {message}'.format(r.status, **resp_dict)
Discussions

AskReddit: Why use requests as opposed to urllib3?

It’s a wrapper for many things you want to do with urllib3 and other libraries like ssl.

This is just an abstraction library for ease.

More on reddit.com
🌐 r/Python
11
17
May 5, 2019
What is the difference between urllib and python requests library?
Urllib is a part of standard library, and in python3 was updated to be usable. So if you don't need to do something urllib doesn't support, there isn't really a reason to reach for a dependency. More on reddit.com
🌐 r/learnpython
2
2
January 1, 2023
Calling .read() on a request returns an empty string
I'm not sure whether this is a bug, or a documentation bug, or not a bug at all, but can anyone tell me why reply ends up as: b'' ? import urllib3 http = urllib3.PoolManager(timeout=65) response = ... More on github.com
🌐 github.com
9
October 9, 2015
Deprecate urllib3.request module
Context After adding the top-level request() method, We have a function named request in urllib3.__init__.py and a module named request(urllib3.request.py). It changes the from request import reque... More on github.com
🌐 github.com
8
June 16, 2021
🌐
GitHub
github.com › urllib3 › urllib3
GitHub - urllib3/urllib3: urllib3 is a user-friendly HTTP client library for Python · GitHub
urllib3 is a powerful, user-friendly HTTP client for Python. urllib3 brings many critical features that are missing from the Python standard libraries: Thread safety. Connection pooling.
Starred by 4K users
Forked by 1.4K users
Languages   Python
🌐
Medium
medium.com › @technige › what-does-requests-offer-over-urllib3-in-2022-e6a38d9273d9
What does requests offer over urllib3 in 2022? | by Nigel Small | Medium
December 10, 2022 - From the start, requests suggests that developers use the global methods get, post, etc, which persist no explicit state between successive usages. The Session object can be used for cases where persistence is required, but documentation for this is also hidden away as “advanced” usage. On the other hand, urllib3 opens its user guide by mentioning the PoolManager This is its (slightly awkwardly-named) carrier of state between successive HTTP calls.
🌐
urllib3
urllib3.readthedocs.io › en › stable › user-guide.html
User Guide - urllib3 2.7.0 documentation
You can use request() to make requests using any HTTP verb: import urllib3 http = urllib3.PoolManager() resp = http.request( "POST", "https://httpbin.org/post", fields={"hello": "world"} # Add custom form fields ) print(resp.data) # b"{\n "form": {\n "hello": "world"\n }, ...
🌐
ZenRows
zenrows.com › homepage › tutorial › python requests vs. urllib3: which one is best?
Python Requests vs. urllib3: Which One Is Best? - ZenRows
February 1, 2024 - Right off the bat, Requests provides a straightforward approach for handling basic authentication with the auth parameter. On the other hand, Urllib3 requires an extra import (the make_headers helper from urllib3.util).
Find elsewhere
🌐
PyPI
pypi.org › project › urllib3 › 1.26.6
urllib3 · PyPI
Much of the Python ecosystem already uses urllib3 and you should too. urllib3 brings many critical features that are missing from the Python standard libraries: Thread safety. Connection pooling. Client-side SSL/TLS verification. File uploads with multipart encoding. Helpers for retrying requests and dealing with HTTP redirects.
      » pip install urllib3
    
Published   Jun 25, 2021
Version   1.26.6
🌐
Stack Abuse
stackabuse.com › guide-to-sending-http-requests-in-python-with-urllib3
Guide to Sending HTTP Requests in Python with urllib3
May 4, 2023 - An HTTP POST request is used for sending data from the client side to the server side. Its most common usage is with file-uploading or form-filling, but can be used to send any data to a server, with a payload: import urllib3 http = urllib3.PoolManager() response = http.request("POST", ...
🌐
ScrapingBee
scrapingbee.com › blog › urllib3-vs-requests
urllib3 vs. Requests: Which HTTP Client is Best for Python? | ScrapingBee
January 3, 2026 - This can make it harder to scrape multiple URLs in parallel. urllib3 is a lower-level package used for sending HTTP requests in Python. It is different from urllib and urllib2, which are Python built-in libraries that need no installation.
🌐
Python
docs.python.org › 3 › library › urllib.request.html
urllib.request — Extensible library for opening URLs
The urllib.request module defines functions and classes which help in opening URLs (mostly HTTP) in a complex world — basic and digest authentication, redirections, cookies and more.
🌐
Quora
quora.com › In-Python-what-are-the-differences-between-the-urllib-urllib2-urllib3-and-requests-modules
In Python, what are the differences between the urllib, urllib2, urllib3 and requests modules? - Quora
Answer (1 of 2): urllib2 provides some extra functionality, namely the [code ]urlopen()[/code] function can allow you to specify headers (normally you'd have had to use httplib in the past, which is far more verbose.) More importantly though, urllib2 provides the [code ]Request[/code] class, whic...
🌐
urllib3
urllib3.readthedocs.io › en › 1.26.3 › reference › urllib3.request.html
Request Methods - urllib3 1.26.3 documentation
Make a request using urlopen() with the fields encoded in the body. This is useful for request methods like POST, PUT, PATCH, etc. When encode_multipart=True (default), then urllib3.encode_multipart_formdata() is used to encode the payload with the appropriate content type.
🌐
iProyal
iproyal.com › blog › urllib3-vs-requests
urllib3 vs Requests: Differences & Best Use Cases
August 14, 2025 - It’s worth using urllib3 as it offers a more robust connection pooling, thread safety, and control over SSL verification. At the same time, it’s still a lightweight third-party library for handling HTTP connections. ... Connection pooling to reuse TCP connections efficiently. Low-level control of request headers, timeouts, and retries.
🌐
GitHub
github.com › urllib3 › urllib3 › issues › 715
Calling .read() on a request returns an empty string · Issue #715 · urllib3/urllib3
October 9, 2015 - import urllib3 http = urllib3.PoolManager(timeout=65) response = http.request('GET', 'http://google.com', decode_content=True) reply = response.read() #reply = response.data # <- this is non-empty however... print("reply.read() returned: " + reply.decode('utf-8')) Reactions are currently unavailable ·
Author   urllib3
🌐
urllib3
urllib3.readthedocs.io › en › stable › reference › index.html
API Reference - urllib3 2.7.0 documentation
urllib3.request() request() Pool Manager · PoolManager · PoolManager.clear() PoolManager.connection_from_context() PoolManager.connection_from_host() PoolManager.connection_from_pool_key() PoolManager.connection_from_url() PoolManager.pools · PoolManager.proxy ·
🌐
ProxiesAPI
proxiesapi.com › articles › how-to-make-http-post-requests-in-python-with-urllib3
How to Make HTTP POST Requests in Python with urllib3 | ProxiesAPI
February 1, 2024 - urllib3 library provides a simple way to make HTTP requests in Python. Use it to send POST requests to APIs and web services with form data.
🌐
PyPI
pypi.org › project › urllib3
urllib3
JavaScript is disabled in your browser. Please enable JavaScript to proceed · A required part of this site couldn’t load. This may be due to a browser extension, network issues, or browser settings. Please check your connection, disable any ad blockers, or try using a different browser
🌐
GitHub
github.com › urllib3 › urllib3 › issues › 2269
Deprecate urllib3.request module · Issue #2269 · urllib3/urllib3
June 16, 2021 - Context After adding the top-level request() method, We have a function named request in urllib3.__init__.py and a module named request(urllib3.request.py). It changes the from request import reque...
Author   urllib3