Almost every API call needs query parameters, an Accept header or an API key, and hand-building URLs causes bugs.
Never build query strings by concatenating text. Pass a dict to params= and Requests URL-encodes keys and values for you, including spaces, & and non-ASCII characters:
requests.get(url, params={"q": "rock & roll", "page": 2})A value that is a list produces a repeated key (tag=a&tag=b), and keys whose value is None are dropped, which is convenient for optional filters. Parameters already in the URL are kept and the new ones appended.
Custom headers go in headers= as a dict. Typical uses:
Accept: application/jsonto ask for JSON,Authorization: Bearer <token>for API tokens (there is also anauth=mechanism, covered later),User-Agentto identify your client; some APIs reject the defaultpython-requests/x.yagent.
Header values must be strings (or bytes); passing an int raises an error. Requests adds its own defaults (User-Agent, Accept-Encoding, Accept, Connection), and your values override them. Setting a header to None removes a default.
Some headers are better left to Requests: it sets Content-Type and Content-Length when you use json=, data= or files=. Setting Content-Type manually for a multipart upload breaks it, because the boundary parameter would be missing.
Inspect r.url or r.request.headers to see exactly what was sent.
Example
import requests
r = requests.get(
"https://httpbin.org/get",
params={"q": "rock & roll", "tag": ["a", "b"], "page": 2, "skip": None},
headers={"Accept": "application/json", "User-Agent": "my-script/1.0"},
timeout=10,
)
print(r.url)
# https://httpbin.org/get?q=rock+%26+roll&tag=a&tag=b&page=2
echo = r.json()
print(echo["args"]) # {'page': '2', 'q': 'rock & roll', 'tag': ['a', 'b']}
print(echo["headers"]["User-Agent"]) # my-script/1.0
print(r.request.headers["Accept-Encoding"]) # gzip, deflate (default; may add br, zstd)Remember
- params= builds and encodes the query string; None values are dropped
- headers= adds or overrides headers; values must be strings
- Let Requests set Content-Type for json=, data= and files=
Watch out for
- Formatting URLs with f-strings like f'{url}?q={term}', which breaks on spaces and &.