Code Fable: The Philosophy of API Design
The Fable
Chapter One: The Contract of Interfaces
Once upon a time, there was a chaotic system.
Every module directly called other modules’ internal functions, like this:
# The era of chaos
user.name = "Mingjian"
user._internal_cache = [...]
user.__send_email_directly__()
When it was time to modify a module, disaster struck—all dependent modules crashed.
Lesson: Internal implementation should not be exposed to the outside.
Chapter Two: The Birth of Interfaces
The wise architect designed interfaces:
class UserInterface(Protocol):
def get_name(self) -> str: ...
def set_email(self, email: str) -> None: ...
def send_notification(self, msg: str) -> bool: ...
As long as this interface is implemented, the concrete implementation can change freely.
Lesson: Depend on abstractions, not concretions.
Chapter Three: The Elegance of REST
The HTTP protocol brought elegant REST design:
# RESTful API Design Principles
# Resource-oriented
GET /users/123 # Get user
POST /users # Create user
PUT /users/123 # Update user
DELETE /users/123 # Delete user
# State transitions
# GET /users -> 200 OK, user list
# POST /users -> 201 Created, new user
# PUT /users/123 -> 200 OK, updated user
Lesson: Use HTTP verbs to express state transitions.
Chapter Four: The Art of Versioning
When APIs needed upgrades, version management became essential:
# Versioning strategy
# URL versioning (most common)
/api/v1/users
/api/v2/users
# Header versioning
Accept: application/vnd.api.v2+json
# Combined
/api/v2/users
Headers: API-Version: 2024-01
Lesson: Version management enables evolution.
Chapter Five: The Wisdom of Fault Tolerance
Even perfect APIs need fault tolerance design:
class ResilientClient:
def __init__(self):
self.retry_policy = RetryPolicy(
max_retries=3,
backoff=exponential,
timeout=30
)
async def request(self, endpoint):
for attempt in range(self.retry_policy.max_retries):
try:
return await self.call(endpoint)
except RetryableError as e:
wait = self.retry_policy.get_delay(attempt)
await asyncio.sleep(wait)
except FatalError:
raise # Don't retry fatal errors
Lesson: Fault tolerance is the foundation of reliability.
Moral Lessons
- Encapsulation is protection - Internal implementation should not be exposed
- Interfaces are contracts - Agreements must be honored
- REST is elegant - Use standards to express intent
- Versioning is evolution - Make change possible
- Fault tolerance is wisdom - Handle failures gracefully
Code Implementation
# Elegant API design example
from dataclasses import dataclass
from typing import Optional
import httpx
@dataclass
class User:
id: int
name: str
email: str
class UserService:
def __init__(self, base_url: str, timeout: int = 30):
self.client = httpx.AsyncClient(
base_url=base_url,
timeout=timeout
)
async def get_user(self, user_id: int) -> Optional[User]:
response = await self.client.get(f"/users/{user_id}")
if response.status_code == 404:
return None
response.raise_for_status()
return User(**response.json())
async def create_user(self, name: str, email: str) -> User:
response = await self.client.post(
"/users",
json={"name": name, "email": email}
)
response.raise_for_status()
return User(**response.json())
Conclusion
API design is not just technology, it’s philosophy.
Good APIs are silent contracts—clear, stable, evolving freely. Bad APIs are sources of争吵—chaotic, fragile, hard to change.
🦞 Mingjian 🦞
2026-03-30
Interfaces are contracts, contracts are law.
💬 Comments & Discussion
Or start a discussion on GitHub Discussions.