Support JSON Schema 2020-12 $dynamicRef
/ $dynamicAnchor
references
#6775
Labels
$dynamicRef
/ $dynamicAnchor
references
#6775
JSON Schema Dynamic References in TypeSpec
This proposal adds support for JSON Schema dynamic references (
$dynamicRef
and$dynamicAnchor
) to the@typespec/json-schema
package.Background and Motivation
JSON Schema 2020-12 introduced
$dynamicRef
and$dynamicAnchor
, which enable polymorphic schema reuse, recursive type specialization, and dynamic resolution of references at runtime. Unlike standard$ref
, which resolves statically and lexically, dynamic references resolve based on the evaluation path. This late-binding mechanism supports complex patterns like recursive polymorphism and context-sensitive schema composition.The Problem Dynamic References Solve
Common scenarios where traditional
$ref
is too rigid:With standard
$ref
, recursive structures always resolve to the original definition, so specialized behavior or constraints in extended types can't be properly enforced. Dynamic references enable the validator to select the right schema depending on where the evaluation started—ensuring proper validation at all nesting levels.This unlocks:
This capability is essential for accurately modeling many real-world domains in APIs, from document management systems to financial services, organization hierarchies to UI component libraries.
Proposal
Add new decorators to the TypeSpec JSON Schema library:
These decorators map directly to JSON Schema 2020-12 keywords and defer all dynamic resolution to the schema consumer.
Examples
Polymorphic Tree Structure
This example demonstrates a recursive tree structure where the
children
property can contain any type of node (baseNode
,FileNode
, orFolderNode
), and the validation correctly handles specialized node types at any level of nesting. Without dynamic references, this polymorphic behavior wouldn't be possible because standard$ref
would always point to the originalNode
definition regardless of context.Reusable Generic Schemas
This example shows how dynamic references enable generic schema patterns where a base collection schema can be specialized for different item types while maintaining proper validation. The
@dynamicRef
decorator allows the schema to adapt based on which specialized item type is being used, providing correct context-specific validation.Component Composition
This demonstrates a UI component composition system where containers can hold any component type, including other containers, and the validation logic correctly applies to all nested components. The dynamic references ensure that specialized component types are properly validated no matter where they appear in the component tree.
Technical Implementation
Library State Keys
Add new state keys in
lib.ts
:Decorator Implementation
Add getters/setters in
decorators.ts
:Schema Generation
Update
#applyConstraints
injson-schema-emitter.ts
:Runtime Behavior and Semantics
@dynamicAnchor("foo")
declarations are permitted and expected for polymorphism.$dynamicRef
will resolve at runtime, based on the closest matching anchor in the instance evaluation path.$ref
is emitted when@dynamicRef
is used—this is a distinct mechanism.Alternative Approaches Considered
1. Combined Decorator
Instead of separate
@dynamicAnchor
and@dynamicRef
decorators, use a combined approach:Pros:
Cons:
2. Using Existing Extension Decorator
The existing
@extension
decorator could handle this without new decorators:Pros:
Cons:
Technical Considerations
1. URI Reference Validation
The implementation should validate that
$dynamicRef
URIs are properly formatted, especially when they include fragments.2. JSON Schema Version Compatibility
The
$dynamicRef
and$dynamicAnchor
keywords were introduced in JSON Schema 2020-12. The implementation should ensure it's using this schema version or newer.3. Schema Resolution
Special care must be taken to ensure that dynamic anchors and references are properly resolved during schema evaluation. This may require coordination with JSON Schema validators used in conjunction with TypeSpec.
4. Circular Reference Handling
Dynamic references can easily create circular references. The implementation should handle these appropriately without causing infinite recursion during schema generation.
Optional Enhancements
@schemaId(...)
could improve cross-file anchor resolution.@dynamicRefTo(Foo)
decorator could help reduce string usage.Real-World Use Cases
1. Document Management Systems
Document management systems commonly represent folder hierarchies where folders can contain other folders or documents. Dynamic references allow proper validation of this structure with type-specific validations at any nesting level.
2. Financial Account Hierarchies
Financial systems often model account hierarchies where accounts can contain sub-accounts with specialized validation rules.
3. UI Component Libraries
UI design systems use component hierarchies where containers can hold other containers and basic components.
4. Organization Structures
Organizations have hierarchical structures with different types of units at different levels.
Benefits
True Polymorphism: Enable proper validation of recursive structures with specialization at any level.
Generic Schema Patterns: Create reusable patterns that adapt to their context, promoting code reuse and consistency.
Precise Inheritance Modeling: Accurately model inheritance relationships and specialized validations in complex object hierarchies.
Flexible Composition: Build complex schemas from simpler building blocks while maintaining proper validation at all levels.
Accurate Domain Modeling: Represent real-world hierarchical relationships with proper type-specific validation rules.
Future-Proof Schemas: Align with the latest JSON Schema standards and capabilities.
Limitations
Schema Complexity: Dynamic references introduce a higher level of complexity in schema design and understanding.
Validator Support: Not all JSON Schema validators may fully support dynamic references yet.
Performance Considerations: Schema validation with dynamic references may be more computationally intensive.
Learning Curve: Developers need to understand the difference between lexical and dynamic scoping to use these features effectively.
Resolution Deferred: TypeSpec can't check if a referenced anchor actually exists – resolution is handled at runtime.
Correct Bundling Required: Poorly structured schema emission (e.g., bundling two anchors of same name incorrectly) could result in unexpected behavior.
Checklist
The text was updated successfully, but these errors were encountered: