Exdantic runtime schemas let you build validation contracts dynamically from data or configuration.

Runtime Schema Types

Exdantic runtime layer includes:

Create a Dynamic Schema

fields = [
  {:name, :string, [required: true, min_length: 2]},
  {:age, :integer, [optional: true, gteq: 0]},
  {:tags, {:array, :string}, [optional: true, min_items: 1]}
]

schema = Exdantic.Runtime.create_schema(fields,
  name: "UserRuntime",
  title: "Runtime User",
  description: "Generated at runtime",
  strict: true
)

Validate:

{:ok, validated} = Exdantic.Runtime.validate(%{name: "Jane", age: 31}, schema)

Generate JSON Schema:

json = Exdantic.Runtime.to_json_schema(schema)

Dynamic Field Definition Format

Accepted tuples:

  • {field_name, type}
  • {field_name, type, opts}

Common field opts:

  • required, optional, default
  • description, example, examples
  • standard constraints (min_length, gteq, etc.)

DynamicSchema Utility APIs

Exdantic.Runtime.DynamicSchema includes helpers:

  • new/4
  • get_field/2
  • field_names/1
  • required_fields/1
  • optional_fields/1
  • strict?/1
  • update_config/2
  • add_field/3
  • remove_field/2
  • summary/1

Enhanced Runtime Schema

Use create_enhanced_schema/2 to add runtime model validators and computed fields:

schema =
  Exdantic.Runtime.create_enhanced_schema(
    [
      {:name, :string, [required: true]},
      {:email, :string, [required: true]}
    ],
    model_validators: [
      fn data -> {:ok, %{data | name: String.trim(data.name)}} end
    ],
    computed_fields: [
      {:email_domain, :string, fn data -> {:ok, data.email |> String.split("@") |> List.last()} end}
    ],
    strict: true
  )

{:ok, result} = Exdantic.Runtime.validate_enhanced(%{name: " Jane ", email: "jane@x.com"}, schema)

Enhanced runtime schemas keep runtime functions in an internal function registry when anonymous functions are used.

EnhancedSchema Utility APIs

Exdantic.Runtime.EnhancedSchema supports:

  • create/2
  • validate/3
  • to_json_schema/2
  • info/1
  • add_model_validator/2
  • add_computed_field/4
  • process_model_validators/1
  • process_computed_fields/2

Unified Runtime Validator

Use Exdantic.Runtime.Validator when callers should not care if schema is dynamic or enhanced:

{:ok, validated} = Exdantic.Runtime.Validator.validate(input, runtime_schema)
json = Exdantic.Runtime.Validator.to_json_schema(runtime_schema)
info = Exdantic.Runtime.Validator.schema_info(runtime_schema)

Phase 6 Runtime Helpers

Runtime module also includes advanced helpers:

  • create_enhanced_schema_v6/2
  • validate_enhanced_v6/3

These can add provider compatibility testing, performance metadata, and JSON Schema checks in one call.

Error Semantics

Runtime validation returns the same structured error shape as compile-time schemas (Exdantic.Error).

Strict mode behaves similarly: unknown keys produce :additional_properties errors.

When Runtime Schemas Are the Right Tool

Choose runtime schemas when:

  • Fields are generated from external metadata
  • Inputs differ per tenant, pipeline stage, or task
  • You need map-based validation contracts without compile-time module generation

Choose compile-time schemas when contracts are stable and shared.

Next Guides

  • guides/05_type_adapter_wrapper_root_schema.md
  • guides/06_json_schema_and_resolvers.md