APIs Explained Simply
What an API is, and what comes back when you ask
In this lesson
An API is an agreement between two programs: one says what it can be asked for, the other asks. Instead of a web page built for human eyes, you get back plain data your code can use. This lesson covers the vocabulary, endpoints, requests, responses, JSON, and status codes, so the next lesson’s code has something to hang on.
Explain it like I’m 5
An API is a menu for software. It lists what you can order and what turns up on the plate. You don’t get to see the kitchen.
An API is an agreement, not a website
When you visit a website, a server sends HTTP back as HTML: headings, styling, layout, everything a browser needs to draw a page. An API answers the same kind of request with data only, because the thing asking is a program, not a person.
That difference is the whole point. Scraping a web page means digging your data out of presentation you didn’t ask for and that changes whenever a designer touches it. An API hands you the data directly, in a shape the provider has promised to keep stable.
Endpoints, requests, and responses
An endpoint is one URL that does one job. A weather service might expose /current for right now and /forecast for the week ahead. You send a request to an endpoint; the server sends back a response.
A request carries more than a URL. It has a method saying what you want done (GET to read, POST to create, and others you’ll meet in a later lesson), optional query parameters narrowing the question, and headers carrying metadata such as who you are.
https://api.example.com/search?q=python&page=2
https://api.example.com the service
/search the endpoint
?q=python a query parameter
&page=2 another query parameter
JSON is what usually comes back
Most APIs answer in JSON. It looks almost exactly like a mix of Python dictionaries and lists, which is why it feels so natural to work with once it reaches your code: objects become dicts, arrays become lists, and the rest are strings, numbers, booleans, and nulls.
Real responses are usually nested. A value can be another object, or a list of objects. Reading them is just repeated indexing, one layer at a time.
{
"name": "London",
"main": { "temp": 12.5, "humidity": 81 },
"weather": [ { "description": "light rain" } ]
}
Below is a parsed API response. Print the city name, the temperature, and the weather description, one per line. Watch the nesting.
response = {
"name": "London",
"main": {"temp": 12.5, "humidity": 81},
"weather": [{"description": "light rain"}],
}
# TODO: print the city, then the temperature, then the description
print(response["name"])
main is a dict, so index it twice. weather is a list, so take [0] before asking for "description".
response = {
"name": "London",
"main": {"temp": 12.5, "humidity": 81},
"weather": [{"description": "light rain"}],
}
print(response["name"])
print(response["main"]["temp"])
print(response["weather"][0]["description"])
London
12.5
light rain
Status codes tell you what happened
Every response carries a three-digit status code. You do not need to memorize them, only the families:
- 2xx, it worked.
200 OKis the everyday success. - 4xx, you got it wrong.
404means no such thing;401and403mean you are not allowed;429means you asked too often. - 5xx, they got it wrong. The server broke. Retrying later is reasonable.
The distinction that matters: 4xx is your bug, 5xx is theirs. Checking the code before you touch the body is what separates a script that fails clearly from one that crashes on confusing nonsense.
Common mistake: Expecting an API to return a web page
Both arrive over the same protocol from the same kind of URL, so it’s easy to assume they’re the same thing.
Read the documentation for the response shape. An API endpoint returns data, normally JSON, not HTML. If you got HTML back, you probably called the website rather than the API.
Common mistake: Treating a JSON response as a string to pick apart
It arrives as text, so slicing and searching it looks like the obvious move.
Parse it once into Python objects, then use normal dict and list access. Never hand-parse JSON with string methods, it breaks the moment a field moves or a value contains a comma.
Common mistake: Ignoring the status code
The happy path works while you’re building, so the check feels like paperwork.
Check the status before reading the body. A 404 or 500 body will not contain your data, and the error you get later will not point at the real cause.
What does an API return, compared with a normal web page?
A web page is built for eyes; an API answers with data built for code, most often JSON.
A response comes back with status 404. What does that tell you?
404 is a 4xx code, meaning the problem is in the request. The body will be an error message, not your data.
Given the response {"main": {"temp": 12.5}}, how do you read the temperature in Python?
main holds another dict, so you index twice, once for the outer key and once for the inner one.
Mini exercise (easy)
Write summarize(response) that takes a parsed weather response and returns a single line like London: 12.5C, light rain. Reach into the nested main dict and the weather list.
Now you. Edit the starter code below, then Run it, everything happens in the browser.
response = {
"name": "Paris",
"main": {"temp": 18.0, "humidity": 55},
"weather": [{"description": "clear sky"}],
}
def summarize(response):
return "" # TODO: "Paris: 18.0C, clear sky"
print(summarize(response))
Pull the three values out into named variables first, then build the string with an f-string. Remember weather is a list, so index [0] before the key.
response = {
"name": "Paris",
"main": {"temp": 18.0, "humidity": 55},
"weather": [{"description": "clear sky"}],
}
def summarize(response):
city = response["name"]
temp = response["main"]["temp"]
description = response["weather"][0]["description"]
return f"{city}: {temp}C, {description}"
print(summarize(response))
Paris: 18.0C, clear sky
assert summarize({"name": "Oslo", "main": {"temp": -3.5}, "weather": [{"description": "snow"}]}) == "Oslo: -3.5C, snow", "summarize should work for any response"
print("✓ Looks good!")