Case Study: How APIs Work — Functions All the Way Down
The Big Picture
You've just learned to write functions — small, reusable pieces of code with clear inputs and outputs. Here's something that might surprise you: the entire internet runs on the same principle, just scaled up.
When you check the weather on your phone, your weather app doesn't have a weather station on the roof. It calls a function — but the function lives on a server thousands of miles away. When you log into a website with your Google account, that website calls a function on Google's servers. When you ask a chatbot a question, the chatbot calls a function in an AI system.
These remote functions are called APIs — Application Programming Interfaces. And at their core, they work exactly like the functions you wrote in this chapter: they take inputs (parameters), do some work, and return outputs (return values).
What Is an API?
An API is a set of functions that one program makes available to other programs. Think of it as a menu at a restaurant:
- The menu lists what you can order (the available functions).
- Your order specifies what you want (the arguments).
- The kitchen does the work (the function body — which you can't see).
- Your food is delivered to your table (the return value).
You don't need to know how the kitchen works. You don't need to know the recipe. You just need to know: 1. What functions are available (the API documentation) 2. What inputs each function expects (the parameters) 3. What each function returns (the return type)
Sound familiar? That's a docstring.
APIs Are Functions: A Concrete Example
Let's compare a local function with what an API call looks like conceptually:
Your Local Function
def get_weather(city):
"""Return the current temperature for a city.
Parameters:
city (str): The city name.
Returns:
dict: Weather data including temperature and conditions.
"""
# In real life, this would check some data source
weather_data = {
"city": city,
"temperature": 72,
"conditions": "Sunny",
"humidity": 45
}
return weather_data
# Call the function
result = get_weather("San Francisco")
print(f"It's {result['temperature']}°F and {result['conditions']} in {result['city']}.")
It's 72°F and Sunny in San Francisco.
The Same Concept as an API Call
# This is what an actual API call looks like (simplified — we'll cover
# the real syntax in Chapter 21)
# Instead of calling a local function:
# result = get_weather("San Francisco")
#
# You call a remote function over the internet:
# response = requests.get("https://api.weather.com/current",
# params={"city": "San Francisco"})
# result = response.json()
#
# The structure is identical:
# - Function name: get_weather vs. /current
# - Parameter: "San Francisco" vs. params={"city": "San Francisco"}
# - Return value: dict vs. JSON (which Python converts to a dict)
The pattern is the same:
1. Name the operation you want (get_weather / /current)
2. Pass in the data it needs ("San Francisco")
3. Get back the result (a dictionary of weather data)
The only difference is where the function executes — on your computer vs. on a server somewhere.
The Layers of Abstraction
Here's where it gets interesting. When your weather app shows you the temperature, here's what's actually happening — each layer is a function calling another function:
Your Weather App
└── calls → get_weather_for_display(city, units)
└── calls → weather_api.get_current(city)
└── calls → http_client.get(url, params)
└── calls → socket.connect(server_address)
└── calls → operating_system.send_tcp_packet(data)
└── calls → network_driver.transmit(bytes)
└── sends electrical signals through your Wi-Fi...
That's at least seven layers of functions, each hiding the complexity of the layer below it. Your app code says get_weather_for_display("San Francisco", "fahrenheit") and doesn't think about TCP packets, network sockets, HTTP protocols, or electrical signals.
This is abstraction. The same concept you learned in section 6.1, but applied at massive scale.
How Python Libraries Use This Pattern
You've already used functions from Python's standard library. Here's how they form layers of abstraction:
# Layer 1: You call a high-level function
average = sum([85, 92, 78]) / len([85, 92, 78])
# But sum() is itself a function that internally loops through items:
# def sum(iterable):
# total = 0
# for item in iterable:
# total += item # += calls __add__() on the number
# return total
# And __add__() eventually calls CPU instructions for arithmetic.
# You never think about any of this — that's the point.
When you call print("Hello"), here's a simplified version of what happens:
print()converts the argument to a string (callsstr())str()looks up the object's__str__method (a function!)print()writes the string tosys.stdout(a file object)sys.stdout.write()calls the operating system's write function- The OS passes the bytes to your terminal application
- Your terminal renders the text on screen
Six layers of functions. You type print("Hello"). Abstraction handles the rest.
A Taste of What's Coming
In Chapter 21, you'll actually write code that calls real APIs. Here's a preview of what that looks like — notice how similar it is to calling a regular function:
# This code won't run without the 'requests' library installed
# and a valid API key. It's shown here to illustrate the pattern.
# import requests
# # Calling a remote function is remarkably similar to a local one:
# # Local function call:
# # result = calculate_average([85, 90, 78])
# # Remote API call:
# # response = requests.get(
# # "https://api.openweathermap.org/data/2.5/weather",
# # params={
# # "q": "San Francisco", # Argument: which city
# # "units": "imperial", # Argument: temperature scale
# # "appid": "your_api_key" # Argument: authentication
# # }
# # )
# # weather = response.json()
# # print(f"Temperature: {weather['main']['temp']}°F")
The mental model is the same: name the operation, provide the inputs, get the output. Functions all the way down.
Real-World API Examples
Here are some APIs you probably use every day without realizing it:
| Service | What It Does | Function-Like Pattern |
|---|---|---|
| Google Maps | Directions between two points | get_directions(origin, destination, mode) returns route data |
| Spotify | Search for a song | search(query, type="track") returns matching songs |
| Twitter/X | Post a tweet | create_post(text, media=None) returns post ID |
| OpenAI | Generate text | complete(prompt, model="gpt-4") returns generated text |
| Stripe | Charge a credit card | create_charge(amount, currency, source) returns transaction |
Every one of these follows the same pattern you've learned: inputs go in, processing happens (hidden behind the abstraction), and outputs come back.
Why This Matters for Your Career
Understanding that APIs are just functions — the same concept you learned today — has profound implications:
-
You can learn any API quickly. Once you know how functions work (inputs, outputs, documentation), you can read any API's docs and start using it. The skills transfer directly.
-
You can build APIs yourself. In a web development course, you'll learn to create functions that other programs can call over the internet. The function design principles from section 6.8 — single responsibility, clear naming, good documentation — apply directly to API design.
-
You understand modern software architecture. Every modern application — from mobile apps to AI systems — is built by composing API calls. A food delivery app might call ten different APIs: authentication, restaurant search, menu display, payment processing, driver dispatch, GPS tracking, notifications, analytics, customer support, and ratings. Each is a set of functions, each maintained by a different team.
Discussion Questions
-
The case study describes APIs as "remote functions." What are the key differences between calling a local function and calling a remote API? Think about things that could go wrong with the remote version that can't go wrong with a local function. (Hint: networks aren't always reliable.)
-
Abstraction lets you use things without understanding their internals. When is this a strength? When could it become a problem? (Hint: what happens when the abstraction "leaks" — when the hidden complexity affects the behavior you can see?)
-
The study shows seven layers between a weather app and the electrical signals on Wi-Fi. Why don't developers write all seven layers themselves? What would software development look like without these layers of abstraction?
-
Consider an AI chatbot like ChatGPT. From the user's perspective, describe it as if it were a function: what are the inputs (parameters)? What is the output (return value)? What complexity is hidden behind the abstraction? How does this relate to the theme "tools you build today power AI"?
-
You've probably heard the phrase "standing on the shoulders of giants." How does function-based abstraction enable this in software development? Give a specific example of how your work in this chapter "stands on the shoulders" of functions written by Python's developers.
Mini-Project
Design (but don't implement — you don't have the tools yet) an API for a music streaming service. Define at least five functions with: - A clear function name (verb + noun) - Parameters with types and descriptions - Return value description - A one-line docstring
For example:
def search_songs(query, genre=None, limit=10):
"""Search the music catalog and return matching songs.
Parameters:
query (str): Search term (song title, artist, or lyrics).
genre (str or None): Optional genre filter.
limit (int): Maximum number of results (default 10).
Returns:
list: A list of dictionaries, each containing 'title', 'artist',
'album', 'duration_seconds', and 'song_id'.
"""
pass # Implementation would talk to a database
Write five more functions that a music streaming API would need. Think about what operations users perform: playing songs, creating playlists, following artists, rating songs, getting recommendations.
References
- The concept of APIs as organized collections of functions is foundational to modern software engineering. For a beginner-friendly introduction, see: Gazarov, P. (2016). "What is an API? In English, please." freeCodeCamp. (Tier 2)
- The "layers of abstraction" view of computer systems is presented formally in: Tanenbaum, A. S. (2016). Structured Computer Organization, 6th Edition. Pearson. (Tier 1)
- For the connection between functions and web APIs, see: Fielding, R. T. (2000). "Architectural Styles and the Design of Network-based Software Architectures." Doctoral dissertation, UC Irvine. This dissertation defined REST, the most common API architectural style. (Tier 1)