BRYME TECH
SEPTEMBER 2026 · THE TOOL DESKPractical technology. No theatre.
THE BRYME

Practical guide · verified against the real thing

How to call an API with Python (standard library only)

In one line: urllib.request from first principles: headers that matter, timeouts that save you, query parameters that don't get mangled, and where the requests library fits.

You do not need a third-party library to call an API from Python — the standard library's urllib.request does the whole job, and learning it first means you understand what every fancier library is doing for you. This piece is the working pattern: build a request, set the headers that matter, always set a timeout, read the response.

The minimal real call

import json
import urllib.request

url = "https://api.github.com/zen"
req = urllib.request.Request(url, headers={"User-Agent": "bryme-demo/1.0"})

with urllib.request.urlopen(req, timeout=10) as resp:
    print("Status:", resp.status)
    body = resp.read().decode("utf-8")

print(body)

Three deliberate details. The User-Agent header: many APIs reject or throttle default Python clients, and a named, honest identifier is both polite and required by some providers. The timeout: without it, a stuck server can hang your program indefinitely — ten seconds is a sane default for most APIs. And the context manager (with): it closes the connection deterministically instead of leaving cleanup to luck. The response body arrives as bytes; .decode("utf-8") turns it into text, and if the endpoint promises JSON, json.loads on that text gives you data structures — the full move is in parsing JSON in Python.

Query parameters without the string surgery

Hand-building URLs with f-strings breaks the first time a value contains a space or an ampersand. urlencode does the escaping correctly:

from urllib.parse import urlencode
import json
import urllib.request

params = urlencode({"q": "json parsing", "per_page": "3"})
url = "https://api.github.com/search/repositories?" + params
req = urllib.request.Request(url, headers={"User-Agent": "bryme-demo/1.0"})

with urllib.request.urlopen(req, timeout=10) as resp:
    results = json.loads(resp.read().decode("utf-8"))

for item in results["items"]:
    print(item["full_name"])

This is also where URL-encoding stops being trivia: urlencode percent-encodes every value the way the server expects — the same transformation as the URL encoder tool.

Where requests fits

The third-party requests library is the community favourite, and for good reason: requests.get(url, params=..., timeout=10) compresses the ceremony while keeping the same shape — headers, parameters, timeouts, then .json() on the response. Install it with pip install requests when a project justifies a dependency. Everything you learned with urllib transfers directly, including the part that matters most when calls go wrong: the error-handling ladder.

Sources

Next

Related on this desk.