Intro – What you’ll learn and who this is for
Calling a web API is one of the most common tasks for a Python developer. In this tutorial you’ll see how to:
- Send a GET request to fetch data.
- Send a POST request with a JSON body.
- Guard the call with timeouts so your program never hangs.
- Detect and handle common HTTP errors.
All of this is demonstrated against the free testing service httpbin.org, which echoes back whatever you send it. The guide is written for beginners who have written a few lines of Python before and want to start talking to APIs right away.
Part 1 – Installing requests and making a simple GET
| Step | Command / Code | What it does |
|---|---|---|
| 1 | pip install requests |
Installs the de‑facto HTTP client library. |
| 2 | python<br>import requests<br>response = requests.get('https://httpbin.org/get')<br>print(response.status_code)<br>print(response.json())<br> |
Sends a GET request and prints the status code and JSON payload returned by httpbin. |
Why requests?
It abstracts away the low‑level urllib boilerplate, lets you pass parameters, headers, and JSON payloads with a single function call, and raises clear exceptions when something goes wrong.
Running the snippet
python - <<'PY'
import requests
resp = requests.get('https://httpbin.org/get')
print('Status:', resp.status_code)
print('Body:', resp.json())
PY
You should see 200 as the status and a JSON object containing fields like url, origin, and headers.
Part 2 – POSTing JSON data
Most APIs expect a JSON body on a POST (or PUT) request. requests makes that a one‑liner:
payload = {'name': 'Alice', 'age': 30}
resp = requests.post('https://httpbin.org/post', json=payload)
print(resp.status_code)
print(resp.json()['json']) # echoed payload
- The
json=argument tellsrequeststo serialize the dictionary to JSON and set theContent-Type: application/jsonheader automatically. - httpbin returns the parsed JSON under the key
jsonin its response payload, which we print to verify the round‑trip.
Part 3 – Timeouts and error handling
A production‑ready API call never trusts the network. Two concepts are essential:
| Concept | How to use in requests |
Typical value |
|---|---|---|
| Timeout | requests.get(url, timeout=5) |
5 seconds (adjust per API) |
| Error handling | try/except requests.exceptions.RequestException as e: |
Catches all request‑related errors |
Example with full error handling
import requests
from requests.exceptions import RequestException, Timeout, HTTPError
url = 'https://httpbin.org/status/404' # forces a 404 response
try:
resp = requests.get(url, timeout=3)
# Raise an exception for 4xx/5xx status codes
resp.raise_for_status()
except Timeout:
print('⚠️ Request timed out')
except HTTPError as http_err:
print(f'⚠️ HTTP error: {http_err}') # e.g., 404 Client Error
except RequestException as err:
print(f'⚠️ Other request problem: {err}')
else:
print('✅ Success:', resp.json())
raise_for_status()converts non‑2xx responses into anHTTPError.- The
exceptchain isolates timeout problems from other HTTP errors, making debugging easier.
Hands‑on example – A complete 20‑line script
Save the following as api_demo.py and run it with python api_demo.py. The script:
- Performs a GET.
- Performs a POST with JSON.
- Demonstrates timeout handling on an endpoint that deliberately sleeps.
- Catches and prints any error.
#!/usr/bin/env python3
import json
import requests
from requests.exceptions import RequestException, Timeout, HTTPError
BASE = 'https://httpbin.org'
def get_demo():
resp = requests.get(f'{BASE}/get', timeout=4)
resp.raise_for_status()
print('GET →', resp.json()['url'])
def post_demo():
payload = {'user': 'bob', 'score': 42}
resp = requests.post(f'{BASE}/post', json=payload, timeout=4)
resp.raise_for_status()
print('POST echoed →', resp.json()['json'])
def timeout_demo():
# /delay/10 waits 10 seconds; we set timeout to 2 seconds
try:
requests.get(f'{BASE}/delay/10', timeout=2)
except Timeout:
print('Timeout demo: request timed out as expected')
def main():
try:
get_demo()
post_demo()
timeout_demo()
except (HTTPError, RequestException) as e:
print('❌ API call failed:', e)
if __name__ == '__main__':
main()
What to expect
GET → https://httpbin.org/get
POST echoed → {'user': 'bob', 'score': 42}
Timeout demo: request timed out as expected
The script is exactly 20 lines of executable code (blank lines and comments excluded), showing that a robust API client can be tiny.
Common mistakes / troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
ImportError: No module named requests |
requests not installed |
Run pip install --user requests |
requests.exceptions.ConnectionError |
DNS typo or no internet | Verify the URL (https://httpbin.org) and network connectivity |
requests.exceptions.HTTPError: 404 Client Error |
Wrong endpoint or missing trailing slash | Double‑check the path; most httpbin URLs need a leading / |
requests.exceptions.ReadTimeout even for fast endpoints |
Timeout value too low | Increase timeout (e.g., timeout=10) |
| JSON payload not received on server side | Sent data as data= instead of json= |
Use json=payload so the header is set correctly |
Try it yourself – Mini exercise
- Open a new file
weather_demo.py. - Use the public API
https://api.open-meteo.com/v1/forecast(no API key required). - Query the current temperature for Berlin (
latitude=52.52,longitude=13.41). - Print the temperature in Celsius, handling timeouts and HTTP errors as shown above.
Hint: The endpoint expects query parameters like ?latitude=52.52&longitude=13.41¤t_weather=true.
What’s next
- Authentication – Learn how to add Bearer tokens or API keys to headers.
- Pagination – Retrieve large result sets by following
nextlinks. - Async requests – Speed up many calls with
httpxoraiohttp. - Testing APIs – Mock
requestswithresponseslibrary for unit tests.
Bookmark this page for a quick 20‑line API cheat sheet.