Skip to content
Laviyx Learn

Try

Python course menu

Working With APIs in Python: requests, JSON, Parameters and Errors

Learn to use web APIs in Python with the requests library: send GET and POST requests, read JSON responses, pass query parameters, check status codes, handle timeouts and errors, and use API keys safely.

Intermediate8 min readUpdated
On this page

An API (Application Programming Interface) lets programs talk to other programs. Web APIs let your Python code get weather forecasts, exchange rates, GitHub data, or send messages, usually by sending an HTTP request to a URL and receiving JSON back. The requests library makes this simple.

Setup#

requests is a third-party library. Install it (ideally inside a virtual environment):

Terminal
python -m pip install requests

The examples use JSONPlaceholder, a free fake API built for learning. Its responses never change, so you will see the same output as below.

Your first GET request#

Python
import requests

response = requests.get("https://jsonplaceholder.typicode.com/todos/1", timeout=10)

print(response.status_code)
print(response.headers["Content-Type"])

data = response.json()
print(data)
print(data["title"], data["completed"])
Output
200
application/json; charset=utf-8
{'userId': 1, 'id': 1, 'title': 'delectus aut autem', 'completed': False}
delectus aut autem False
  • requests.get(url) sends the request and returns a response object.
  • status_code 200 means success.
  • .json() parses the JSON body into Python dictionaries and lists (see JSON).
  • timeout=10 stops waiting after 10 seconds. Always set a timeout; without one, a slow server can freeze your program forever.

HTTP status codes#

CodeMeaning
200OK
201Created (after a successful POST)
400Bad request: your data was invalid
401 / 403Not authenticated / not allowed
404Not found
429Too many requests: slow down
500+Server error: try again later

Query parameters#

Pass filters as a dictionary with params; requests builds the URL for you:

Python
r = requests.get("https://jsonplaceholder.typicode.com/posts",
                 params={"userId": 1}, timeout=10)
print(r.url)

posts = r.json()
print(len(posts), posts[0]["id"], posts[0]["title"][:30])
Output
https://jsonplaceholder.typicode.com/posts?userId=1
10 1 sunt aut facere repellat provi

Sending data with POST#

Create something on the server by sending JSON:

Python
new_post = {"title": "Learning Python", "body": "APIs are fun", "userId": 1}
r = requests.post("https://jsonplaceholder.typicode.com/posts", json=new_post, timeout=10)

print(r.status_code)
print(r.json())
Output
201
{'title': 'Learning Python', 'body': 'APIs are fun', 'userId': 1, 'id': 101}

json= converts your dictionary to JSON and sets the right headers. (JSONPlaceholder pretends to save it and returns a new id; nothing is really stored.)

Handling errors#

A missing resource does not raise an exception by itself; check the status:

Python
r = requests.get("https://jsonplaceholder.typicode.com/posts/99999", timeout=10)
print(r.status_code, r.ok, r.json())

try:
    r.raise_for_status()
except requests.HTTPError as e:
    print("HTTPError:", e)
Output
404 False {}
HTTPError: 404 Client Error: Not Found for url: https://jsonplaceholder.typicode.com/posts/99999

raise_for_status() turns 4xx and 5xx responses into exceptions. A robust helper handles network problems too:

Python
def get_user(user_id):
    try:
        r = requests.get(f"https://jsonplaceholder.typicode.com/users/{user_id}", timeout=5)
        r.raise_for_status()
        return r.json()
    except requests.Timeout:
        print("The request timed out")
    except requests.HTTPError as e:
        print("HTTP error:", e.response.status_code)
    except requests.RequestException as e:
        print("Network problem:", type(e).__name__)
    return None

user = get_user(1)
print(user["name"], "|", user["address"]["city"], "|", user["company"]["name"])
print(get_user(999))
Output
Leanne Graham | Gwenborough | Romaguera-Crona
HTTP error: 404
None

requests.RequestException is the parent of all requests errors, including ConnectionError when a server cannot be reached at all.

A real public API#

Real APIs work the same way. GitHub's API, for example:

Python
r = requests.get("https://api.github.com/repos/python/cpython", timeout=10)
repo = r.json()
print(repo["full_name"], "|", repo["language"], "|", repo["html_url"])
Output
python/cpython | Python | https://github.com/python/cpython

The response also contains numbers that change constantly, such as stargazers_count. Each API documents its URLs, parameters and fields; reading those docs is part of the job.

API keys and authentication#

Most real APIs require a key or token, usually sent in a header:

Python
import os

headers = {"Authorization": f"Bearer {os.environ['WEATHER_API_KEY']}"}
r = requests.get("https://api.example.com/v1/forecast",
                 params={"city": "Pune"}, headers=headers, timeout=10)

Respect each API's rate limits: if you receive status 429, wait before retrying.

Without installing anything#

The standard library's urllib.request can make simple requests too, though requests is much friendlier:

Python
import json
import urllib.request

with urllib.request.urlopen("https://jsonplaceholder.typicode.com/todos/2", timeout=10) as resp:
    data = json.load(resp)
print(data["id"], data["title"])
Output
2 quis ut nam facilis et officia qui

Common mistakes#

Practice#

Practice exercise

Fetch all todos for userId 1 from https://jsonplaceholder.typicode.com/todos, print how many are completed out of the total, and list the ids of the first five that are not completed.

Show hint

Use params={"userId": 1}, then count with sum(1 for t in todos if t["completed"]).

Show solution
Python
import requests

r = requests.get("https://jsonplaceholder.typicode.com/todos",
                 params={"userId": 1}, timeout=10)
r.raise_for_status()
todos = r.json()

done = sum(1 for t in todos if t["completed"])
print(f"{done} of {len(todos)} completed")
print([t["id"] for t in todos if not t["completed"]][:5])
Output
11 of 20 completed
[1, 2, 3, 5, 6]

Key takeaway#

Finished this lesson?