Chapter 12

APIs

12.0 Intro · 12.1 API Basics · 12.2 API Reliability

← → or Space to navigate · F for fullscreen

12.1 API Basics

HTTP · requests.get() · JSON · query parameters · offline fixtures

What is an API?

An API (application programming interface) is a contract that lets programs talk to each other. A REST-style web API uses HTTP endpoints to exchange structured data, often JSON.

HTTP Method Action
GET Read data
POST Create data
PUT Replace data
PATCH Update part of data
DELETE Remove data

Status codes

Code Meaning
200 OK — success
201 Created
400 Bad request
401 Unauthorized
404 Not found
429 Rate limited
500 Server error

requests.get() Pattern and JSON

import requests

url = "https://api.example.test/weather"
params = {"city": "Chicago", "units": "fahrenheit"}

response = requests.get(url, params=params,
                        timeout=10)
response.raise_for_status()   # raise on 4xx/5xx

data = response.json()
print(data["temperature"])

Offline-safe fixtures

class DemoResponse:
    def __init__(self, payload, status_code=200):
        self._payload = payload
        self.status_code = status_code

    def raise_for_status(self):
        if self.status_code >= 400:
            raise requests.HTTPError(self.status_code)

    def json(self):
        return self._payload

response = DemoResponse({"temperature": 72.5})

JSON Text and Python Objects

A response body arrives as text. response.json() calls json.loads() on it for you.

Function Converts
json.loads(text) JSON string to dict / list
json.dumps(obj) dict / list to JSON string
JSON Python
"text" (double quotes only) 'text' or "text"
true, false True, False
null None
import json

raw_body = '{"city": "Chicago", "raining": false, "alerts": null}'
weather = json.loads(raw_body)
print(weather["raining"], weather["alerts"])
print(weather.get("humidity", "not reported"))

summary_text = json.dumps({"city": weather["city"],
                           "raining": weather["raining"]})
print(summary_text)
False None
not reported
{"city": "Chicago", "raining": false}

12.2 API Reliability

POST · headers · nested JSON · pagination · retry · validation

Authentication & API Keys

import os

# Store secrets in environment variables — never in code
api_key = os.environ["MY_API_KEY"]

# Bearer token
headers = {"Authorization": f"Bearer {api_key}"}

# X-API-Key header
headers = {"X-API-Key": api_key}

response = requests.get(url, headers=headers,
                        timeout=10)

POST with JSON body

payload = {
    "name": "Alice",
    "role": "student",
}

response = requests.post(
    "https://api.example.test/users",
    headers={"Authorization": f"Bearer {api_key}"},
    json=payload,   # auto-encodes and sets Content-Type
    timeout=30,
)

Nested JSON, Pagination, and Retry

Defensive parsing

payload = {
    "user": {
        "profile": {"department": "Analytics"}
    }
}

department = (
    payload
    .get("user", {})
    .get("profile", {})
    .get("department", "unknown")
)

Exponential backoff retry

import time

def get_with_retry(url, retries=3):
    for attempt in range(retries):
        try:
            r = requests.get(url, timeout=10)
            r.raise_for_status()
            return r.json()
        except requests.RequestException as e:
            if attempt == retries - 1:
                raise
            time.sleep(2 ** attempt)   # 1, 2, 4 s

Chapter 12 — Quick Reference

Concept Key syntax / notes
GET request requests.get(url, params={}, timeout=10)
POST request requests.post(url, json={}, headers={})
Prepared request requests.Request(...).prepare()
Raise on error .raise_for_status()
Parse JSON .json() → dict/list
Safe access data.get("key", default)
Auth header {"Authorization": f"Bearer {token}"}
API key Store in os.environ, never hard-coded
Pagination Loop until next_page or cursor is empty
Retry Exponential backoff with a max retry count

End of Chapter 12

Next: Chapter 13 — Abstract Data Structures

stacks · queues · trees · graphs · ADT interface vs implementation