Deployed my Python API to production last Friday. All tests green. Felt good about it.
Monday morning support messages me. API returning 500 errors for about 30% of requests. Tests still passing locally.
Great.
What broke
My code parsed JSON from an external API:
import requests
def get_user_data(user_id):
response = requests.get(f"https://api.example.com/users/{user_id}")
data = response.json()
return {
'name': data['profile']['name'],
'email': data['contact']['email'],
'age': data['profile']['age']
}
Tests mocked the API response with perfect JSON. Every field present. Proper nesting. Exactly what I expected and nothing like what actually came back half the time.
Production API sometimes returned incomplete data. Missing profile object. Missing contact email. Still valid JSON, just structured differently.
My tests never checked for this because I wrote happy path mocks like an idiot.
def test_get_user_data():
mock_response = {
'profile': {'name': 'John', 'age': 30},
'contact': {'email': 'john@example.com'}
}
# This never happens in real life
result = get_user_data(123)
assert result['name'] == 'John'
Real API had:
- New users missing profile data
- Deactivated accounts missing contact info
- International users with different field names
- Probably other stuff I still haven't found
My perfect mock data taught me nothing.
What actually worked
def get_user_data(user_id):
response = requests.get(f"https://api.example.com/users/{user_id}")
data = response.json()
# Get with defaults instead of assuming structure
profile = data.get('profile', {})
contact = data.get('contact', {})
return {
'name': profile.get('name', 'Unknown'),
'email': contact.get('email', None),
'age': profile.get('age', None)
}
Defensive access patterns everywhere. Also added tests with missing fields:
def test_get_user_data_missing_profile():
mock_response = {'contact': {'email': 'test@example.com'}}
# Entire profile object gone
result = get_user_data(123)
assert result['name'] == 'Unknown'
def test_get_user_data_empty_response():
mock_response = {}
# API returned but gave us nothing
result = get_user_data(123)
assert result['name'] == 'Unknown'
Should've written these first honestly. Testing only perfect scenarios is like practicing catch with yourself.
Still figuring out what other edge cases exist. Prod keeps finding them for me.
Top comments (0)