19 / 65 · 14 API Testing Fundamentals · Response Validation← prev⊞ allnext →☰ Read as one page
3.3Response Structure Validation
Verify that the response body contains all expected fields with correct types, and does not contain sensitive data.
def test_list_users_structure(api):
r = api.get("/users")
data = r.json()
# Top-level pagination structure
assert {"items", "total", "page", "per_page"}.issubset(data.keys())
assert isinstance(data["total"], int)
assert isinstance(data["items"], list)
# Individual item structure
if data["items"]:
user = data["items"][0]
assert {"id", "name", "email", "created_at"}.issubset(user.keys())
assert isinstance(user["id"], int)
assert isinstance(user["name"], str)
assert "@" in user["email"]
# No sensitive data
assert "password_hash" not in user
assert "ssn" not in user
assert "credit_card" not in user
def test_user_detail_structure(api, create_user):
user = create_user()
r = api.get(f"/users/{user['id']}")
data = r.json()
# Detailed response may have more fields
required = {"id", "name", "email", "role", "created_at", "updated_at"}
assert required.issubset(data.keys()), f"Missing: {required - data.keys()}"
# Type checking
assert isinstance(data["id"], int)
assert isinstance(data["role"], str)
assert data["role"] in {"admin", "editor", "viewer"}
Schema Validation with jsonschema
For more rigorous validation, use JSON Schema:
from jsonschema import validate
USER_SCHEMA = {
"type": "object",
"required": ["id", "name", "email", "role", "created_at"],
"properties": {
"id": {"type": "integer"},
"name": {"type": "string", "minLength": 1},
"email": {"type": "string", "format": "email"},
"role": {"type": "string", "enum": ["admin", "editor", "viewer"]},
"created_at": {"type": "string", "format": "date-time"},
},
"additionalProperties": False # No unexpected fields
}
def test_user_matches_schema(api, create_user):
user = create_user()
r = api.get(f"/users/{user['id']}")
validate(instance=r.json(), schema=USER_SCHEMA)