How to Validate JSON Output Against a Dict Schema in Python
Validate JSON-like data against a simple dict schema with type checking and descriptive error messages using only the Python standard library.
Python code
82 linesfrom typing import Dict, Any, List, Union
def validate_json(data: Any, schema: Dict[str, str]) -> List[str]:
"""
Validate JSON-like data against a simple dict schema.
Schema format: {field_name: expected_type} where type is one of:
'str', 'int', 'float', 'bool', 'list', 'dict', 'any'
Returns list of validation errors.
"""
errors = []
if not isinstance(data, dict):
return ["Root must be a dict"]
for field, expected_type in schema.items():
if field not in data:
errors.append(f"Missing field: {field}")
continue
value = data[field]
type_map = {
'str': str,
'int': int,
'float': (int, float),
'bool': bool,
'list': list,
'dict': dict,
}
if expected_type != 'any':
expected = type_map[expected_type]
if not isinstance(value, expected):
errors.append(
f"Field '{field}' should be {expected_type}, got {type(value).__name__}"
)
return errors
def main():
schema = {
"name": "str",
"age": "int",
"score": "float",
"active": "bool",
"tags": "list",
"metadata": "dict"
}
# Valid example
valid_data = {
"name": "Alice",
"age": 30,
"score": 87.5,
"active": True,
"tags": ["python", "json"],
"metadata": {"level": "advanced"}
}
# Invalid example with wrong types and missing field
invalid_data = {
"name": "Bob",
"age": "thirty", # should be int
"score": 92, # int instead of float - allowed via int,float
"active": "yes", # should be bool
# "tags" missing
"metadata": {"level": "beginner"}
}
print("=== Valid Data ===")
valid_errors = validate_json(valid_data, schema)
print("Errors:", valid_errors if valid_errors else "None - validation passed")
print("\n=== Invalid Data ===")
invalid_errors = validate_json(invalid_data, schema)
for error in invalid_errors:
print(f" - {error}")
print(f"Total errors found: {len(invalid_errors)}")
if __name__ == "__main__":
main()
Output
=== Valid Data ===
Errors: None - validation passed
=== Invalid Data ===
- Field 'age' should be int, got str
- Field 'active' should be bool, got str
- Missing field: tags
Total errors found: 3
How it works
The validate_json function iterates through each field in the schema dict and checks presence and type against the provided data. The type_map dictionary maps schema type names to Python built-in types for isinstance checks. Using (int, float) for the float type allows both integers and floats, which is common in JSON payloads. The function returns a list of error strings, making it easy to surface validation issues in API responses or LLM output checks. This pattern is a lightweight alternative to pydantic when you only need basic type validation without full object modeling.
Common mistakes
- Using `json.loads` on data that's already a dict — validate native dicts directly
- Forgetting that bool is a subclass of int in Python, so ordering matters in isinstance checks
- Not validating nested structures recursively when fields are dicts or lists
- Assuming float validation should reject integers instead of allowing them via (int, float)
Variations
- Use `pydantic` with a BaseModel for automatic validation and coercion of nested structures
- Recursively validate nested dict/list fields by calling validate_json on nested values
Real-world use cases
- Validating structured output from LLM JSON responses before inserting into a database.
- Schema-checking API webhook payloads at runtime to surface bad requests early.
- Verifying config files or environment variables match expected types during service startup.
Sponsored
More from AI & LLM integration patterns
- Cache LLM Completions by Hashing the Prompt in Python easy
- Chain of Thought Prompting in Python: Step-by-Step Reasoning Demo easy
- Circuit Breaker Pattern in Python for LLM API Calls medium
- Cosine Similarity to Retrieve Top K Chunks in Python easy
- Demonstrate Prompt Injection Bypass in Python easy
- How to Accumulate Streamed Tokens into a Final String in Python easy
Keep learning
Related tutorials and quizzes for this topic.