Practical Exercise 7
Hands-On
Use AI to integrate third-party APIs efficiently
2026 WayUp
1
Have AI read and understand API documentation
2
Generate type-safe API client code
3
Implement proper error handling
4
Write integration tests with mocking
# Weather API Documentation
## Endpoints
### GET /weather/current
Get current weather for a location.
**Parameters:**
- city (string, required): City name
- units (string, optional): "metric" or "imperial", default: "metric"
**Response 200:**
{
"city": "Paris",
"temperature": 22.5,
"humidity": 65,
"description": "partly cloudy",
"wind_speed": 12.3
}
**Response 404:** City not found
**Response 429:** Rate limit exceeded (100 req/hour)
# models.py
from pydantic import BaseModel, Field
from enum import Enum
class Units(str, Enum):
METRIC = "metric"
IMPERIAL = "imperial"
class WeatherResponse(BaseModel):
city: str
temperature: float
humidity: int = Field(ge=0, le=100)
description: str
wind_speed: float = Field(ge=0)
class WeatherRequest(BaseModel):
city: str = Field(min_length=1, max_length=100)
units: Units = Units.METRIC
# client.py
import httpx
from tenacity import retry, stop_after_attempt, wait_exponential
class WeatherClient:
def __init__(self, api_key: str, base_url: str = "https://api.weather.com"):
self.api_key = api_key
self.base_url = base_url
self._client = httpx.AsyncClient(
base_url=base_url,
headers={"X-API-Key": api_key},
timeout=10.0
)
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, max=10))
async def get_current_weather(self, city: str, units: Units = Units.METRIC) -> WeatherResponse:
response = await self._client.get(
"/weather/current",
params={"city": city, "units": units.value}
)
if response.status_code == 404:
raise CityNotFoundError(f"City not found: {city}")
if response.status_code == 429:
raise RateLimitError("Rate limit exceeded")
response.raise_for_status()
return WeatherResponse(**response.json())
import pytest
import respx
from httpx import Response
@pytest.fixture
def weather_client():
return WeatherClient(api_key="test-key")
@pytest.mark.asyncio
@respx.mock
async def test_get_current_weather_success(weather_client):
respx.get("https://api.weather.com/weather/current").mock(
return_value=Response(200, json={
"city": "Paris",
"temperature": 22.5,
"humidity": 65,
"description": "sunny",
"wind_speed": 10.0
})
)
result = await weather_client.get_current_weather("Paris")
assert result.city == "Paris"
assert result.temperature == 22.5
@pytest.mark.asyncio
@respx.mock
async def test_city_not_found_raises_error(weather_client):
respx.get("https://api.weather.com/weather/current").mock(
return_value=Response(404)
)
with pytest.raises(CityNotFoundError):
await weather_client.get_current_weather("FakeCity")
You've built a production-ready API client
Course Complete - Keep practicing AIDD!
2026 WayUp - way-up.io