Files
kennethreitz.org/data/software/requests.md
T
kennethreitz d325d34c90 Fix syntax highlighting dark mode, use uv pip install
Sync highlight.js theme with dark mode toggle via MutationObserver.
Use github-dark-dimmed for dark mode. Override backgrounds to
match site theme.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 04:17:33 -04:00

4.5 KiB

Requests: HTTP for Humans

Requests is the most downloaded Python package on Earth. Over 30 million installs a day. It exists because urllib2 was hostile to humans, and HTTP shouldn't be.

$ uv pip install requests

What It Looks Like

import requests

# GET a webpage.
r = requests.get("https://api.github.com/user", auth=("user", "pass"))

print(r.status_code)
# 200

print(r.headers["content-type"])
# 'application/json; charset=utf-8'

print(r.json())
# {'login': 'user', 'id': 123456, ...}

That's it. No handlers. No openers. No abstractions between you and the thing you're trying to do.

Before Requests

This is what HTTP looked like in Python before Requests existed:

import urllib2
import base64

request = urllib2.Request("https://api.github.com/user")
base64string = base64.b64encode("%s:%s" % ("user", "pass"))
request.add_header("Authorization", "Basic %s" % base64string)

try:
    result = urllib2.urlopen(request)
    print result.getcode()
    print result.read()
except urllib2.URLError, e:
    print e

Seven lines of ceremony to do what Requests does in one. Three imports. Manual base64 encoding for basic auth. An exception hierarchy that tells you what went wrong but not how to fix it. The interface told your subconscious "this is hard" before you'd accomplished anything.

The Philosophy

Requests was built on a simple conviction: if you're making the developer feel stupid, the problem is your API, not your developer.

# POST with JSON data.
r = requests.post("https://httpbin.org/post", json={"key": "value"})

# Upload a file.
r = requests.post("https://httpbin.org/post", files={"file": open("report.csv", "rb")})

# Set a timeout. Because hanging forever is not a feature.
r = requests.get("https://api.example.com/slow", timeout=5)

# Sessions persist cookies across requests.
s = requests.Session()
s.get("https://httpbin.org/cookies/set/session/value")
r = s.get("https://httpbin.org/cookies")
print(r.json())
# {'cookies': {'session': 'value'}}

# Custom headers.
r = requests.get("https://api.example.com/data", headers={"Accept": "application/xml"})

# SSL verification on by default. Because security shouldn't be opt-in.
r = requests.get("https://example.com")
# ✓ SSL certificate verified automatically.

Every method does what you'd expect. Every default is sensible. Every error message tells you what happened and what to do about it. The API fits in your head because it was designed to fit in your head.

What It Taught Me

I was twenty-one when I wrote the first version of Requests. I had no degree, no credentials, no professional network. I was working at McDonald's the year before. The library became the standard because it solved a real problem simply, and the community recognized it.

That experience became the foundation for everything I've built since. The "for humans" philosophy started as API design and became a life philosophy. It shaped how I think about marriage, mental health tools, Bible study applications, and what we owe each other when we build things people think through.

It also nearly broke me. The same intensity that produced Requests produced the conditions for my worst mental health crises. The engine was the same. It just had two outputs.

Fun fact: the Requests logo is a tattoo on my right arm.

Install

uv pip install requests

Resources