API Requests in Python
In this lesson: Call REST APIs in Python with the requests library — GET, POST, JSON, headers and error handling — with output. In Hindi & English.
What is an API?
An API (Application Programming Interface) lets one program ask another program for data or actions over the internet. A weather app asks a weather API for today’s temperature; a shop app asks the server for products and sends orders back. Most web APIs speak HTTP and reply with JSON.
| HTTP method | Meaning | Example |
|---|---|---|
| GET | Read data | List of products |
| POST | Create something | Place an order |
| PUT / PATCH | Update | Change address |
| DELETE | Remove | Cancel order |
In this lesson we use the free CodingEasily practice API for a sweet shop: https://codingeasily.in/api/sweets/. It is real, needs no key and never stores your data, so you can experiment freely.
pip install requests
Your first GET request
import requests
URL = "https://codingeasily.in/api/sweets/"
response = requests.get(URL, timeout=10)
print("status :", response.status_code)
print("type :", response.headers["Content-Type"])
products = response.json() # JSON text → Python list of dicts
print("items :", len(products))
for p in products[:3]:
print(f"{p['id']}. {p['name']:<14} ₹{p['price']}/{p['unit']} stock {p['stock']}")status_code200 means OK..json()converts the reply into Python lists and dicts.- Always pass
timeout=; without it a dead server can freeze your program forever.
Query parameters
Do not build URLs by joining strings. Pass a dictionary to params and requests encodes it correctly (spaces, Hindi, &).
import requests
URL = "https://codingeasily.in/api/sweets/"
r = requests.get(URL, params={"category": "box"}, timeout=10)
print(r.url)
print([p["name"] for p in r.json()])
r = requests.get(URL, params={"q": "kaju"}, timeout=10)
print([p["name"] for p in r.json()])Status codes and errors
| Code | Meaning | What your program should do |
|---|---|---|
| 200 / 201 | OK / Created | Use the data |
| 400 / 422 | Your request is wrong | Show the server’s message to the user |
| 401 / 403 | Not logged in / not allowed | Ask for login or a valid API key |
| 404 | Not found | Show “not found” |
| 429 | Too many requests | Wait and retry |
| 500–599 | Server problem | Retry later; log the error |
import requests
URL = "https://codingeasily.in/api/sweets/"
def get_product(product_id):
try:
r = requests.get(URL, params={"id": product_id}, timeout=5)
r.raise_for_status() # turns 4xx/5xx into an exception
return r.json()
except requests.exceptions.HTTPError:
return f"HTTP {r.status_code}: {r.json().get('error')}"
except requests.exceptions.Timeout:
return "Server is too slow, try again"
except requests.exceptions.ConnectionError:
return "No internet connection"
print(get_product(2)["name"])
print(get_product(99))A 404 or 500 response is still a “successful” call. Call raise_for_status() or check r.ok before using the data.
Timeouts in practice
The practice API can simulate a slow server with ?delay= (milliseconds). Here the server needs 2 seconds but we wait only 1:
import requests
URL = "https://codingeasily.in/api/sweets/"
try:
requests.get(URL, params={"delay": 2000}, timeout=1)
except requests.exceptions.Timeout:
print("Timed out after 1 second – show a friendly message instead of freezing")
r = requests.get(URL, params={"delay": 500}, timeout=5)
print("with a longer timeout:", r.status_code)POST: sending JSON (placing an order)
import requests
URL = "https://codingeasily.in/api/sweets/"
order = {
"name": "Aarti Gupta",
"phone": "9829012345",
"items": [{"id": 1, "qty": 0.5}, {"id": 7, "qty": 2}],
"coupon": "SWEET10",
"mode": "pickup",
}
r = requests.post(URL, json=order, timeout=10) # json= sets the header and encodes for you
print(r.status_code)
data = r.json()
for item in data["items"]:
print(f" {item['name']:<17} x{item['qty']:<4} ₹{item['amount']}")
print("subtotal", data["subtotal"], "| discount", data["discount"], "| delivery", data["delivery"], "| total", data["total"])
bad = requests.post(URL, json={"name": "A", "phone": "12345", "items": []}, timeout=10)
print(bad.status_code, bad.json()["fields"])The server validates everything and calculates the prices itself – the client only sends ids and quantities. That is how real e-commerce APIs protect against fake prices.
Headers, API keys and sessions
import os
import requests
session = requests.Session() # reuses the connection → faster
session.headers.update({
"User-Agent": "school-report/1.0 (contact@example.com)",
"Authorization": f"Bearer {os.environ.get('MY_API_KEY', 'demo-key')}",
})
r = session.get("https://codingeasily.in/api/sweets/", params={"id": 3}, timeout=10)
print(r.status_code, r.json()["name"])
print("sent header:", r.request.headers["User-Agent"])Keep keys in environment variables or a .env file that is not committed to Git. A key pushed to GitHub is found by bots within minutes.
Automatic retries for unreliable servers
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
retry = Retry(total=3, backoff_factor=0.5, status_forcelist=[429, 500, 502, 503, 504])
session = requests.Session()
session.mount("https://", HTTPAdapter(max_retries=retry))
session.mount("http://", HTTPAdapter(max_retries=retry))
try:
session.get("https://codingeasily.in/api/sweets/", params={"fail": 1}, timeout=5)
except requests.exceptions.RetryError:
print("Gave up after 3 retries – the server keeps returning 500")?fail=1 makes the practice API return HTTP 500. The session retries 3 times with growing waits (0.5 s, 1 s, 2 s) before giving up.
Mini project: low-stock report
import csv
import requests
URL = "https://codingeasily.in/api/sweets/"
products = requests.get(URL, timeout=10).json()
low = sorted((p for p in products if p["stock"] < 15), key=lambda p: p["stock"])
with open("reorder.csv", "w", newline="", encoding="utf-8-sig") as f:
w = csv.writer(f)
w.writerow(["Product", "Stock", "Status"])
for p in low:
w.writerow([p["name"], p["stock"], "OUT OF STOCK" if p["stock"] == 0 else "Reorder"])
print(open("reorder.csv", encoding="utf-8-sig").read())Common mistakes
| Mistake | Fix |
|---|---|
| No timeout | Always timeout=10 (or a tuple (3, 10)) |
| Using data without checking status | r.raise_for_status() or if r.ok: |
data= instead of json= for JSON APIs | Use json=payload |
| Building URLs with + and f-strings | Use params={...} |
| API key in code / GitHub | Environment variable or .env (git-ignored) |
| Calling an API in a tight loop | Respect rate limits; use sleep, caching or batch endpoints |
Practice tasks
- Print all milk sweets (
?category=milk) sorted by rating. - Ask the user for a product id with
input()and print its details or “not found”. - Place a delivery order without a coupon and print the delivery charge returned by the server.
- Try a coupon on an order below ₹500 and print the server’s error message for the coupon field.
Summary
requests.get(url, params=…, timeout=…)reads;requests.post(url, json=…)sends JSON.r.json()gives Python data; checkr.status_code/raise_for_status().- Handle Timeout and ConnectionError; add retries for flaky servers.
- Sessions reuse connections and headers; keep API keys out of code.
