Yesterday I published 8 Python API wrappers to GitHub. Each one took about 20 minutes. They all follow the same pattern.
Here's the template.
The Pattern
Every API client I build has:
- A single class
- A base URL
- A private
_get()method - Public methods that return clean dictionaries
- Under 100 lines total
import requests
class MyAPIClient:
BASE = "https://api.example.com/v1"
def __init__(self, api_key=None):
self.api_key = api_key
def _get(self, endpoint, **params):
if self.api_key:
params["apikey"] = self.api_key
resp = requests.get(f"{self.BASE}/{endpoint}", params=params)
resp.raise_for_status()
return resp.json()
def get_something(self, query):
data = self._get("search", q=query)
return [{"title": r["title"], "url": r["url"]} for r in data["results"]]
That's it. No complex abstractions. No decorator magic. No metaclasses.
The 8 Clients
| Client | API | Auth | Lines |
|---|---|---|---|
| CoinGecko | Crypto prices | None | 45 |
| Open-Meteo | Weather | None | 55 |
| Hacker News | HN stories | None | 40 |
| Wikipedia | Articles | None | 50 |
| Alpha Vantage | Stocks | Free key | 65 |
| SEC EDGAR | SEC filings | None | 60 |
| FRED | Economic data | Free key | 50 |
| NewsAPI | News search | Free key | 45 |
All of them follow the exact same pattern. All are under 100 lines.
Why This Approach Works
1. No dependencies beyond requests
Most API clients on PyPI pull in 5-10 dependencies. Mine need exactly one: requests. Less to install, less to break.
2. Read the entire codebase in 2 minutes
When a library is 45 lines, you can read every line of code before using it. No hidden surprises.
3. Easy to modify
Need to add a method? Copy the pattern, change the endpoint. Need to add caching? Wrap _get(). Need rate limiting? Add a sleep to _get().
4. No abstraction leaks
Returning plain dictionaries means no custom objects to learn, no serialization issues, no repr surprises. Just data.
The Anti-Pattern: Over-Engineered Clients
I've seen API clients with:
- Custom exception hierarchies (10+ exception classes)
- Async + sync versions of every method
- Built-in caching with 5 configuration options
- Response objects with 20+ methods
- Connection pooling with retry logic
For what? Making GET requests to a REST API.
When You DO Need More
The simple pattern breaks down when:
- You need to handle authentication flows (OAuth, refresh tokens)
- You're making hundreds of requests per second
- The API has complex pagination
- You need webhook handling
For everything else: 50 lines is enough.
The Unified Client
I also built a single client that combines all 8 APIs:
from data_fetcher import DataFetcher
df = DataFetcher()
df.crypto("bitcoin") # CoinGecko
df.weather(40.71, -74.01) # Open-Meteo
df.hn_top(5) # Hacker News
df.stock("AAPL") # Alpha Vantage
df.news("AI") # NewsAPI
One import, all the data.
What APIs would you want a simple Python client for?
All clients: github.com/Spinov001
Top comments (0)