APIs and Async · Building an API Client · lesson 10 of 12
Wrapping an API in a class
about 30 minutes · free · runs in your browser
Step 1 of 2
One place that knows about the API
Scattering requests.get calls through a codebase means the base URL, the token and
the error handling are scattered too. A client class puts them in one place:
class WeatherClient:
def __init__(self, base_url, token=None):
self.base_url = base_url
self.token = token
def _headers(self):
if self.token:
return {"Authorization": "Bearer " + self.token}
return {}
def get_weather(self, city):
r = requests.get(
self.base_url + "/weather",
params={"city": city},
headers=self._headers(),
)
r.raise_for_status()
return r.json()
Now changing the base URL, adding a header or adding retries is one edit. The methods
speak the language of the problem — get_weather("London") — rather than the language
of HTTP.
Your turn: build WeatherClient with get_weather(city) returning the parsed
body, and get_temperature(city) returning just the number or None for an unknown
city.
You start from this, and edit it in the browser:
import fake_requests as requests
class WeatherClient:
def __init__(self, base_url="https://api.pylearn.dev"):
pass
def get_weather(self, city):
pass
def get_temperature(self, city):
pass
Step 2 of 2
Why this whole course used a stub
Every lesson here talked to a scripted service rather than the internet, and that was not a limitation of the browser — it is how you should test an API client anywhere.
A test that makes real network calls is slow, needs credentials, fails when someone else's server is down, and cannot reproduce a 500 on demand. A fake makes every one of those cases instant and deterministic.
The technique is to inject the thing that talks to the network, rather than reaching for it directly:
class Client:
def __init__(self, http): # <- passed in, not imported
self.http = http
def temperature(self, city):
return self.http.get("/weather", params={"city": city}).json()["temp_c"]
Now a test passes a stub with a scripted answer, and production passes the real thing. This is dependency injection, and it is the difference between a client you can test and one you can only hope about.
Your turn: write Client taking an http object, with temperature(city)
returning the number and is_warm(city) returning True above 20. Then write
FakeHttp — a stub with a scripted table — so the class can be tested with no network
at all.
You start from this, and edit it in the browser: