#!/usr/bin/env python3 """ JSON Schema Validator CLI A simple command-line tool to validate JSON files against JSON schemas. Usage: python json_schema_cli.py [--output report.json] """ import json import sys import argparse from typing import Any def load_json(path: str) -> dict | list | None: """Load and parse JSON from file path.""" with open(path, 'r') as f: return json.load(f) def validate_data(data: Any, schema: dict) -> list[str]: """ Validate data against a JSON schema. Returns list of validation errors (empty if valid). """ errors = [] # Basic schema structure check if '$schema' not in schema and 'type' not in schema: errors.append("Schema missing required fields ($schema or 'type')") return errors # Type validation if 'type' in schema: expected_type = schema['type'] actual_type = type(data).__name__ type_map = { 'string': str, 'number': (int, float), 'integer': int, 'boolean': bool, 'array': list, 'object': dict, 'null': type(None) } if expected_type in type_map: expected_py = type_map[expected_type] if not isinstance(data, expected_py): errors.append(f"Type mismatch: expected '{expected_type}', got '{actual_type}'") # Properties validation (for objects) if isinstance(data, dict) and 'properties' in schema: props = schema['properties'] for prop, prop_schema in props.items(): if prop in data: prop_errors = validate_data(data[prop], prop_schema) for err in prop_errors: errors.append(f"Property '{prop}': {err}") elif prop_schema.get('required', False): errors.append(f"Missing required property: '{prop}'") # Items validation (for arrays) if isinstance(data, list) and 'items' in schema: items_schema = schema['items'] for i, item in enumerate(data): item_errors = validate_data(item, items_schema) for err in item_errors: errors.append(f"Item {i}: {err}") # Required fields check if isinstance(data, dict) and 'required' in schema: for req_field in schema['required']: if req_field not in data: errors.append(f"Missing required field: '{req_field}'") return errors def main(): parser = argparse.ArgumentParser(description='Validate JSON against a schema') parser.add_argument('json_file', help='Path to JSON file to validate') parser.add_argument('schema_file', help='Path to JSON schema file') parser.add_argument('--output', '-o', help='Output file for validation report') args = parser.parse_args() try: data = load_json(args.json_file) schema = load_json(args.schema_file) except FileNotFoundError as e: print(f"Error: File not found - {e}") sys.exit(1) except json.JSONDecodeError as e: print(f"Error: Invalid JSON - {e}") sys.exit(1) errors = validate_data(data, schema) report = { 'valid': len(errors) == 0, 'errors': errors, 'data_file': args.json_file, 'schema_file': args.schema_file } if args.output: with open(args.output, 'w') as f: json.dump(report, f, indent=2) print(f"Report written to {args.output}") print(json.dumps(report, indent=2)) sys.exit(0 if report['valid'] else 1) if __name__ == '__main__': main()