Skip to main content

Schema system

The TEN framework uses a schema system to define and validate data structures throughout the runtime environment. Schemas provide type definitions for extension properties and messages. The schema system offers the following key benefits:

  • Type safety - Prevents runtime errors by validating data types before processing
  • Data consistency - Ensures all extensions interpret data structures identically
  • Clear contracts - Provides explicit interface definitions between components
  • Automatic validation - Validates data at runtime without manual checking
  • Cross-language compatibility - Maintains consistent data handling across C++, Go, and Python extensions

TEN schemas differ from standard JSON Schema - they define metadata specific to the TEN runtime's type system and validation requirements, using JSON only as the representation format. Schemas are defined in manifest files and applied automatically when extensions exchange data or access properties.

Schema design principles

The TEN framework schema system follows three core design principles that ensure consistency and prevent conflicts across all schema definitions.

  • Object principle The schema for every field in the TEN framework must be defined as an object. This ensures a structured and consistent format across all schema definitions.


    _5
    {
    _5
    "foo": {
    _5
    "type": "int8"
    _5
    }
    _5
    }

    Incorrect format:


    _3
    {
    _3
    "foo": "int8"
    _3
    }

  • Metadata-only principle The schema defines only metadata, not actual data values. This separation ensures that the schema remains a template for validation and does not mix with data content.

  • Conflict prevention principle In any JSON level containing a TEN schema, all fields must be user-defined, except for reserved fields like ten. This prevents conflicts between user-defined fields and system-defined fields.

    Example with user-defined fields:


    _8
    {
    _8
    "user_timeout": {
    _8
    "type": "int32"
    _8
    },
    _8
    "custom_setting": {
    _8
    "type": "string"
    _8
    }
    _8
    }

    Example with reserved ten field:


    _11
    {
    _11
    "ten": {
    _11
    "framework_metadata": {}
    _11
    },
    _11
    "user_timeout": {
    _11
    "type": "int32"
    _11
    },
    _11
    "custom_setting": {
    _11
    "type": "string"
    _11
    }
    _11
    }

Schema syntax and formatting

All TEN schemas follow consistent formatting rules:

  • Object structure: Each field definition must be an object with a type property
  • Nested properties: Objects use properties to define their field schemas
  • Array items: Arrays use items to define the schema for their elements
  • Type specification: The type field specifies the data type using TEN framework type names

The schema structure directly mirrors the data it describes, making it intuitive to understand the relationship between schema definitions and actual data values.

Schema types and structure

The TEN framework supports both primitive and complex data types in schema definitions, allowing you to describe simple values as well as structured data.

Primitive types

The TEN framework provides fundamental data types that correspond to common programming language primitives:

Numeric types:

  • int8, int16, int32, int64 - Signed integers of various sizes
  • uint8, uint16, uint32, uint64 - Unsigned integers of various sizes
  • float32, float64 - Single and double precision floating-point numbers

Other primitive types:

  • string - Unicode character sequences
  • bool - Binary true/false values
  • buf - Sequences of 8-bit unsigned bytes
  • ptr - Pointers to memory addresses

Primitive type schema syntax:


_11
{
_11
"timeout": {
_11
"type": "int32"
_11
},
_11
"username": {
_11
"type": "string"
_11
},
_11
"enabled": {
_11
"type": "bool"
_11
}
_11
}

Complex types

Complex types enable structured data representation for more sophisticated use cases.

  • Object type represents key-value pairs with string keys:


    _16
    {
    _16
    "config": {
    _16
    "type": "object",
    _16
    "properties": {
    _16
    "host": {
    _16
    "type": "string"
    _16
    },
    _16
    "port": {
    _16
    "type": "int32"
    _16
    },
    _16
    "ssl_enabled": {
    _16
    "type": "bool"
    _16
    }
    _16
    }
    _16
    }
    _16
    }

  • Array type represents collections of elements with the same type:


    _8
    {
    _8
    "servers": {
    _8
    "type": "array",
    _8
    "items": {
    _8
    "type": "string"
    _8
    }
    _8
    }
    _8
    }

Manifest schema integration

The manifest.json file serves as the central location where all schema definitions come together to create a complete extension interface specification.

Complete manifest structure

The manifest file integrates all schema definitions into a single, comprehensive structure that defines your extension's complete interface. A complete manifest includes package metadata, dependencies, and API schemas for all supported message types.

For example, here's a complete manifest structure:


_75
{
_75
"type": "extension",
_75
"name": "media_processor",
_75
"version": "1.2.0",
_75
"dependencies": [
_75
{
_75
"type": "system",
_75
"name": "ten_runtime",
_75
"version": "1.0.0"
_75
}
_75
],
_75
"api": {
_75
"property": {
_75
"max_concurrent_jobs": {
_75
"type": "int32"
_75
},
_75
"output_quality": {
_75
"type": "string"
_75
},
_75
"processing_config": {
_75
"type": "object",
_75
"properties": {
_75
"enable_gpu": {
_75
"type": "bool"
_75
},
_75
"memory_limit_mb": {
_75
"type": "int32"
_75
}
_75
}
_75
}
_75
},
_75
"cmd_in": [
_75
{
_75
"name": "start_processing",
_75
"property": {
_75
"input_file": {
_75
"type": "string"
_75
},
_75
"output_format": {
_75
"type": "string"
_75
}
_75
},
_75
"result": {
_75
"property": {
_75
"job_id": {
_75
"type": "string"
_75
},
_75
"estimated_duration": {
_75
"type": "int32"
_75
}
_75
}
_75
}
_75
}
_75
],
_75
"cmd_out": [],
_75
"data_in": [
_75
{
_75
"name": "progress_update",
_75
"property": {
_75
"job_id": {
_75
"type": "string"
_75
},
_75
"percentage": {
_75
"type": "int8"
_75
}
_75
}
_75
}
_75
],
_75
"data_out": [],
_75
"video_frame_in": [],
_75
"video_frame_out": [],
_75
"audio_frame_in": [],
_75
"audio_frame_out": []
_75
}
_75
}

Combining schemas in manifest.json

When combining different schema types in your manifest, organize them by their purpose and message direction to create a clear and maintainable extension interface.

Organization principles:

  • Properties - Define extension configuration schemas in api.property
  • Commands - Separate incoming (cmd_in) and outgoing (cmd_out) command schemas
  • Data messages - Separate incoming (data_in) and outgoing (data_out) data schemas
  • Media frames - Define video and audio frame schemas for specialized processing

Schema relationships: The schemas work together to create a complete extension interface. Property schemas define configuration, while message schemas define communication protocols. The TEN runtime uses these schemas collectively to validate all data flowing through your extension.

Schema validation in practice

The TEN runtime applies schema validation automatically at key points during extension lifecycle and message processing.

Validation occurs during:

  • Extension initialization - Property values from property.json are validated against property schemas
  • Message routing - Incoming messages are validated against their corresponding schemas before delivery
  • Runtime property updates - Property changes via API calls are validated against schemas
  • Message sending - Outgoing messages are validated before transmission to ensure compatibility

Property schemas

Property schemas define the structure and types for extension configuration data stored in property.json files. These schemas enable type validation and ensure consistent property handling across your TEN application.

Property schemas are defined in the api.property section of your manifest file. Each property name maps to a schema definition that describes its expected type and structure.

For example, given this property data:


_10
{
_10
"database_config": {
_10
"host": "localhost",
_10
"port": 5432,
_10
"credentials": {
_10
"username": "admin",
_10
"password": "secret123"
_10
}
_10
}
_10
}

The corresponding TEN property schema definition is as follows:


_28
{
_28
"api": {
_28
"property": {
_28
"database_config": {
_28
"type": "object",
_28
"properties": {
_28
"host": {
_28
"type": "string"
_28
},
_28
"port": {
_28
"type": "int32"
_28
},
_28
"credentials": {
_28
"type": "object",
_28
"properties": {
_28
"username": {
_28
"type": "string"
_28
},
_28
"password": {
_28
"type": "string"
_28
}
_28
}
_28
}
_28
}
_28
}
_28
}
_28
}
_28
}

The TEN runtime validates property data against this schema to ensure type safety and structural correctness.

This sample schema ensures that:

  • host must be a string value
  • port must be a 32-bit integer
  • credentials must be an object containing string values for username and password

Command schemas

Command schemas define the structure and types for command messages exchanged between extensions. These schemas enable type validation for both command parameters and their expected results, ensuring consistent communication across your TEN application.

Command schemas are defined in the api.cmd_in and api.cmd_out sections of your manifest file. Each command includes a name, property schema for input parameters, and a result schema for the expected response.

For example, given this command message:


_12
{
_12
"ten": {
_12
"name": "process_file",
_12
"seq_id": "123"
_12
},
_12
"file_path": "/data/input.txt",
_12
"compression_level": 5,
_12
"options": {
_12
"preserve_metadata": true,
_12
"output_format": "zip"
_12
}
_12
}

The corresponding TEN command schema definition is as follows:


_41
{
_41
"api": {
_41
"cmd_in": [
_41
{
_41
"name": "process_file",
_41
"property": {
_41
"file_path": {
_41
"type": "string"
_41
},
_41
"compression_level": {
_41
"type": "int8"
_41
},
_41
"options": {
_41
"type": "object",
_41
"properties": {
_41
"preserve_metadata": {
_41
"type": "bool"
_41
},
_41
"output_format": {
_41
"type": "string"
_41
}
_41
}
_41
}
_41
},
_41
"result": {
_41
"property": {
_41
"output_path": {
_41
"type": "string"
_41
},
_41
"file_size": {
_41
"type": "int64"
_41
},
_41
"success": {
_41
"type": "bool"
_41
}
_41
}
_41
}
_41
}
_41
]
_41
}
_41
}

The TEN runtime validates command data against this schema to ensure type safety and structural correctness.

info

The TEN framework allows you to exclude the ten field from your schema definition, as it is reserved and defined by the runtime.

This command schema ensures that:

  • file_path must be a string value
  • compression_level must be an 8-bit integer
  • options must be an object containing a boolean preserve_metadata and string output_format
  • The command result must include a string output_path, 64-bit integer file_size, and boolean success

Data, video frame, and audio frame schemas

The process for defining schemas for data, video frames, and audio frames is similar to that for commands but without the result field.

Next steps

Start implementing schemas in your extensions:

  • Define property schemas for your extension configuration in manifest.json
  • Create message schemas for commands and data exchanges between extensions
  • Test schema validation by providing invalid data during development to ensure your schemas work correctly
  • Review the Type System documentation for detailed information about supported data types and conversion rules

Schemas provide the foundation for type-safe, reliable communication in your TEN applications. Start with simple property schemas and gradually add message schemas as your extension interfaces become more complex.