Composition
This section covers advanced schema composition features in dotjson that enable code reuse, complex patterns, and sophisticated data structures.
Schema References with $defs
References allow you to define a schema once and reuse it multiple times throughout your document. This promotes consistency and maintainability.
Basic Reference Pattern
Define reusable schemas in $defs and reference them with $ref:
{
"type": "object",
"properties": {
"primaryContact": { "$ref": "#/$defs/person" },
"secondaryContact": { "$ref": "#/$defs/person" }
},
"required": ["primaryContact"],
"$defs": {
"person": {
"type": "object",
"properties": {
"firstName": { "type": "string" },
"lastName": { "type": "string" },
"email": { "type": "string", "format": "email" },
"phone": { "type": "string" }
},
"required": ["firstName", "lastName", "email"]
}
}
}{
"primaryContact": {
"firstName": "Alice",
"lastName": "Johnson",
"email": "[email protected]",
"phone": "+1-555-0100"
},
"secondaryContact": {
"firstName": "Bob",
"lastName": "Smith",
"email": "[email protected]",
"phone": "+1-555-0101"
}
}Nested References
References can contain other references, creating modular schemas:
{
"type": "object",
"properties": {
"company": { "$ref": "#/$defs/company" }
},
"required": ["company"],
"$defs": {
"address": {
"type": "object",
"properties": {
"street": { "type": "string" },
"city": { "type": "string" },
"state": { "type": "string" },
"postalCode": { "type": "string" },
"country": { "type": "string" }
},
"required": ["street", "city", "country"]
},
"person": {
"type": "object",
"properties": {
"name": { "type": "string" },
"title": { "type": "string" },
"email": { "type": "string", "format": "email" },
"phone": { "type": "string" }
},
"required": ["name", "email"]
},
"company": {
"type": "object",
"properties": {
"name": { "type": "string" },
"headquarters": { "$ref": "#/$defs/address" },
"ceo": { "$ref": "#/$defs/person" },
"cto": { "$ref": "#/$defs/person" },
"founded": { "type": "integer" }
},
"required": ["name", "headquarters", "ceo"]
}
}
}{
"company": {
"name": "TechCorp Inc.",
"headquarters": {
"street": "100 Innovation Drive",
"city": "San Francisco",
"state": "CA",
"postalCode": "94105",
"country": "USA"
},
"ceo": {
"name": "Jane Doe",
"title": "Chief Executive Officer",
"email": "[email protected]",
"phone": "+1-555-0200"
},
"cto": {
"name": "John Smith",
"title": "Chief Technology Officer",
"email": "[email protected]",
"phone": "+1-555-0201"
},
"founded": 2010
}
}References in Arrays
Use references to define consistent item schemas in arrays:
{
"type": "object",
"properties": {
"team": {
"type": "array",
"items": { "$ref": "#/$defs/employee" },
"minItems": 1
}
},
"required": ["team"],
"$defs": {
"employee": {
"type": "object",
"properties": {
"id": { "type": "string", "pattern": "^EMP-[0-9]{6}$" },
"name": { "type": "string" },
"department": {
"type": "string",
"enum": ["Engineering", "Sales", "Marketing", "HR", "Finance"]
},
"level": {
"type": "string",
"enum": ["Junior", "Mid", "Senior", "Lead", "Principal"]
},
"skills": {
"type": "array",
"items": { "type": "string" },
"minItems": 1,
"maxItems": 10
}
},
"required": ["id", "name", "department", "level"]
}
}
}{
"team": [
{
"id": "EMP-001234",
"name": "Alice Chen",
"department": "Engineering",
"level": "Senior",
"skills": ["Python", "JavaScript", "Docker", "Kubernetes"]
},
{
"id": "EMP-001235",
"name": "Bob Wilson",
"department": "Engineering",
"level": "Mid",
"skills": ["Java", "Spring", "PostgreSQL"]
},
{
"id": "EMP-001236",
"name": "Carol Davis",
"department": "Marketing",
"level": "Lead",
"skills": ["SEO", "Content Strategy", "Analytics"]
}
]
}Important
dotjson only supports internal references (within the same schema). External references like file:// or http:// are not supported.
Recursive Schemas
Recursive schemas allow structures to reference themselves, enabling arbitrarily nested data like trees, graphs, and hierarchies.
Simple Recursion
A basic tree structure with self-referencing nodes:
{
"type": "object",
"properties": {
"name": { "type": "string" },
"value": { "type": "number" },
"children": {
"type": "array",
"items": { "$ref": "#" },
"default": []
}
},
"required": ["name", "value"]
}{
"name": "root",
"value": 100,
"children": [
{
"name": "branch1",
"value": 50,
"children": [
{
"name": "leaf1",
"value": 25,
"children": []
},
{
"name": "leaf2",
"value": 25,
"children": []
}
]
},
{
"name": "branch2",
"value": 50,
"children": []
}
]
}File System Structure
Model hierarchical file systems with recursive schemas:
{
"$defs": {
"file": {
"type": "object",
"properties": {
"name": { "type": "string" },
"type": { "type": "string", "const": "file" },
"size": { "type": "integer", "minimum": 0 },
"modified": { "type": "string", "format": "date-time" }
},
"required": ["name", "type", "size"]
},
"directory": {
"type": "object",
"properties": {
"name": { "type": "string" },
"type": { "type": "string", "const": "directory" },
"contents": {
"type": "array",
"items": {
"anyOf": [
{ "$ref": "#/$defs/file" },
{ "$ref": "#/$defs/directory" }
]
}
}
},
"required": ["name", "type", "contents"]
}
},
"$ref": "#/$defs/directory"
}{
"name": "project",
"type": "directory",
"contents": [
{
"name": "src",
"type": "directory",
"contents": [
{
"name": "main.js",
"type": "file",
"size": 2048,
"modified": "2024-03-15T10:30:00Z"
},
{
"name": "utils",
"type": "directory",
"contents": [
{
"name": "helpers.js",
"type": "file",
"size": 1024,
"modified": "2024-03-14T15:45:00Z"
}
]
}
]
},
{
"name": "README.md",
"type": "file",
"size": 4096,
"modified": "2024-03-15T09:00:00Z"
}
]
}Knowledge Graph
Create interconnected concept networks:
{
"type": "object",
"properties": {
"concept": { "type": "string" },
"definition": { "type": "string", "maxLength": 200 },
"category": {
"type": "string",
"enum": ["fundamental", "derived", "application"]
},
"relatedConcepts": {
"type": "array",
"items": { "$ref": "#" },
"maxItems": 3,
"default": []
}
},
"required": ["concept", "definition", "category"]
}{
"concept": "Machine Learning",
"definition": "A subset of AI where computers learn from data without explicit programming",
"category": "fundamental",
"relatedConcepts": [
{
"concept": "Neural Networks",
"definition": "Computing systems inspired by biological neural networks",
"category": "derived",
"relatedConcepts": [
{
"concept": "Deep Learning",
"definition": "Neural networks with multiple layers for complex pattern recognition",
"category": "application",
"relatedConcepts": []
}
]
},
{
"concept": "Training Data",
"definition": "Labeled examples used to teach machine learning models",
"category": "fundamental",
"relatedConcepts": []
}
]
}Note
Complex recursive schemas can be slow to compile. Consider caching compiled schemas for better performance.
Choice with anyOf
anyOf allows the model to choose from multiple possible schemas, enabling flexible data structures.
Primitive Type Choice
Use when a single field may be represented in multiple primitive encodings (for example, a UUID string or a numeric ID).
{
"type": "object",
"properties": {
"identifier": {
"anyOf": [
{ "type": "string", "format": "uuid" },
{ "type": "integer", "minimum": 1 }
],
"description": "UUID or numeric ID"
},
"timestamp": {
"anyOf": [
{ "type": "string", "format": "date-time" },
{ "type": "integer", "minimum": 0 }
],
"description": "ISO date or Unix timestamp"
}
},
"required": ["identifier", "timestamp"]
}Using UUID and ISO date:
{
"identifier": "550e8400-e29b-41d4-a716-446655440000",
"timestamp": "2024-03-15T10:30:00Z"
}Using integer ID and Unix timestamp:
{
"identifier": 12345,
"timestamp": 1710499800
}Discriminated Object Variants (Tagged Unions)
Use when the overall object shape differs; include a discriminator field (such as a tag or a success flag) to select the active variant.
{
"type": "object",
"properties": {
"status": { "type": "integer" },
"response": {
"anyOf": [
{
"type": "object",
"properties": {
"success": { "type": "boolean", "const": true },
"data": {
"type": "object",
"properties": {
"id": { "type": "string" },
"result": { "type": "string" }
},
"required": ["id", "result"]
}
},
"required": ["success", "data"]
},
{
"type": "object",
"properties": {
"success": { "type": "boolean", "const": false },
"error": {
"type": "object",
"properties": {
"code": { "type": "string" },
"message": { "type": "string" },
"details": { "type": "string" }
},
"required": ["code", "message"]
}
},
"required": ["success", "error"]
}
]
}
},
"required": ["status", "response"]
}Success response:
{
"status": 200,
"response": {
"success": true,
"data": {
"id": "req-123",
"result": "Operation completed successfully"
}
}
}Error response:
{
"status": 400,
"response": {
"success": false,
"error": {
"code": "INVALID_INPUT",
"message": "The provided data is invalid",
"details": "Email field must be a valid email address"
}
}
}Polymorphic Data
Handle different object types in the same field:
{
"type": "object",
"properties": {
"events": {
"type": "array",
"items": {
"anyOf": [
{
"type": "object",
"properties": {
"type": { "type": "string", "const": "click" },
"timestamp": { "type": "integer" },
"x": { "type": "integer" },
"y": { "type": "integer" },
"element": { "type": "string" }
},
"required": ["type", "timestamp", "x", "y", "element"]
},
{
"type": "object",
"properties": {
"type": { "type": "string", "const": "pageview" },
"timestamp": { "type": "integer" },
"url": { "type": "string", "format": "uri" },
"referrer": { "type": "string" }
},
"required": ["type", "timestamp", "url"]
},
{
"type": "object",
"properties": {
"type": { "type": "string", "const": "form_submit" },
"timestamp": { "type": "integer" },
"formId": { "type": "string" },
"fields": {
"type": "object",
"additionalProperties": false
}
},
"required": ["type", "timestamp", "formId", "fields"]
}
]
}
}
},
"required": ["events"]
}{
"events": [
{
"type": "pageview",
"timestamp": 1710499800,
"url": "https://example.com/products",
"referrer": "https://google.com"
},
{
"type": "click",
"timestamp": 1710499810,
"x": 450,
"y": 320,
"element": "button#add-to-cart"
},
{
"type": "form_submit",
"timestamp": 1710499820,
"formId": "checkout-form",
"fields": {
"email": "[email protected]",
"quantity": "2"
}
}
]
}Next Steps
- See Practical Examples for real-world applications.
- Review Constraints for available options.
- Check Structures for basic object and array patterns.