JSON Schema
Validate JSON structure against a schema — API responses, config files, data pipelines.
Schema Structure
Minimal valid JSON Schema — defines an object with required fields
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"hostname": { "type": "string", "pattern": "^[a-z][a-z0-9-]+$" },
"ip": { "type": "string", "format": "ipv4" },
"vlan": { "type": "integer", "minimum": 1, "maximum": 4094 },
"enabled": { "type": "boolean", "default": true }
},
"required": ["hostname", "ip", "vlan"],
"additionalProperties": false
}
String with enum constraint — restrict to known values
{
"role": {
"type": "string",
"enum": ["core", "distribution", "access", "management"]
}
}
Array of objects — e.g., list of interfaces
{
"interfaces": {
"type": "array",
"items": {
"type": "object",
"properties": {
"name": { "type": "string" },
"vlan": { "type": "integer" }
},
"required": ["name"]
},
"minItems": 1
}
}
Nested object — model hierarchical config
{
"dns": {
"type": "object",
"properties": {
"primary": { "type": "string", "format": "ipv4" },
"secondary": { "type": "string", "format": "ipv4" },
"search_domains": {
"type": "array",
"items": { "type": "string" }
}
},
"required": ["primary"]
}
}
Validation with ajv-cli
Validate a JSON file against a schema — exit code 0 means valid
ajv validate -s schema.json -d config.json
Validate multiple files against the same schema
ajv validate -s device-schema.json -d "devices/*.json"
Validate with verbose errors — shows which field failed and why
ajv validate -s schema.json -d config.json --errors=text 2>&1
Validation with Python jsonschema
Validate JSON from stdin using Python jsonschema — useful in pipelines
python3 -c "
import json, sys
from jsonschema import validate, ValidationError
schema = json.load(open('schema.json'))
data = json.load(sys.stdin)
try:
validate(instance=data, schema=schema)
print('Valid')
except ValidationError as e:
print(f'Invalid: {e.message}', file=sys.stderr)
sys.exit(1)
" < config.json
Validate all JSON files in a directory against a schema
for f in configs/*.json; do
python3 -c "
import json, sys
from jsonschema import validate, ValidationError
schema = json.load(open('schema.json'))
data = json.load(open('$f'))
try:
validate(instance=data, schema=schema)
print(f'OK: $f')
except ValidationError as e:
print(f'FAIL: $f — {e.message}', file=sys.stderr)
sys.exit(1)
"
done
Schema for API Responses
Schema for a paginated API response — validates structure before parsing
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"total": { "type": "integer", "minimum": 0 },
"page": { "type": "integer", "minimum": 1 },
"results": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": { "type": "string", "format": "uuid" },
"name": { "type": "string" },
"status": { "type": "string", "enum": ["active", "inactive", "pending"] }
},
"required": ["id", "name", "status"]
}
}
},
"required": ["total", "results"]
}
Schema for Config Files
Schema for an infrastructure inventory config — enforces structure on YAML/JSON configs
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"environment": { "type": "string", "enum": ["production", "staging", "lab"] },
"devices": {
"type": "array",
"items": {
"$ref": "#/$defs/device"
}
}
},
"required": ["environment", "devices"],
"$defs": {
"device": {
"type": "object",
"properties": {
"hostname": { "type": "string", "pattern": "^[a-z][a-z0-9.-]+$" },
"mgmt_ip": { "type": "string", "format": "ipv4" },
"role": { "type": "string", "enum": ["core", "distribution", "access"] },
"vlans": {
"type": "array",
"items": { "type": "integer", "minimum": 1, "maximum": 4094 },
"uniqueItems": true
}
},
"required": ["hostname", "mgmt_ip", "role"]
}
}
}
Common Patterns
oneOf — value must match exactly one subschema (e.g., static vs DHCP)
{
"addressing": {
"oneOf": [
{
"type": "object",
"properties": {
"mode": { "const": "static" },
"ip": { "type": "string", "format": "ipv4" },
"gateway": { "type": "string", "format": "ipv4" }
},
"required": ["mode", "ip", "gateway"]
},
{
"type": "object",
"properties": {
"mode": { "const": "dhcp" }
},
"required": ["mode"]
}
]
}
}
if/then — conditional validation based on a field value
{
"if": {
"properties": { "role": { "const": "core" } }
},
"then": {
"required": ["bgp_asn", "loopback_ip"]
}
}
Quick jq schema check — verify required keys exist before processing
jq -e '.hostname and .ip and .vlan' config.json > /dev/null 2>&1 \
&& echo "Valid" || echo "Missing required fields"