Managing Schema References in Solace Schema Registry

Schema references allow you to create reusable schema components that can be shared across multiple schemas. This promotes modularity, consistency, and reduces duplication in your schema definitions. You can use Solace Schema Registry to add, use, and manage schema references, with support for protocol-specific behaviors and validation considerations.

The following sections provide detailed information about:

Overview of Schema References

Schema references define relationships between schemas where one schema depends on or includes another. This capability is essential for building complex data models while keeping your schema definitions modular and easy to maintain.

About Schema References

A schema reference is a link from one schema artifact to another within Solace Schema Registry. References make it possible to define common data types once and reuse them across multiple schemas. You can use references to:

  • Create hierarchical schema structures with parent-child relationships
  • Maintain consistency across related schemas by centralizing shared definitions
  • Simplify schema evolution by updating referenced schemas independently

Schema references allow you to treat schema components as building blocks, encouraging reuse and reducing duplication.

Storing References in Solace Schema Registry

When you add a schema that includes references, Solace Schema Registry stores reference details as metadata alongside the schema content. Each reference includes the following information:

Field Description

Group ID

The artifact group containing the referenced schema.

Artifact ID

The unique identifier of the referenced schema.

Version

The specific version of the referenced schema.

Reference Name

A name that identifies the reference. Best practice is to match the $ref value used in the schema content, though the registry does not validate this match.

This design lets the registry manage both the reference metadata and the schema content independently. As a result, the registry can validate that referenced schemas exist before accepting a new schema, track which schemas depend on others, and prevent deletion of any schema that is still referenced.

Benefits of Using Schema References

Schema references provide several important benefits:

  • Reusability—Define common structures once and reference them from multiple schemas, reducing duplication and maintenance overhead.
  • Modularity—Break complex schemas into smaller, manageable components that can be developed and tested independently.
  • Consistency—Ensure that shared data structures remain consistent across your entire schema ecosystem.
  • Maintainability—Update a referenced schema in one place and have the changes automatically apply to all schemas that reference it.
  • Version Control—Track dependencies between schema versions and ensure compatibility across your schema graph.

Understanding Schema References

Different schema formats use distinct mechanisms to express references within their schema content. Solace Schema Registry currently supports references for JSON Schema and Apache Avro. While both formats enable reusable, modular definitions, they represent and resolve references in different ways.

JSON Schema References

In JSON Schema, references are expressed using the $ref keyword, which points to another schema or definition. A $ref can refer to a schema defined within the same document, an external file, or a specific definition in another schema.

Behavior in Schema Registry

Solace Schema Registry requires explicit coordination between $ref statements in the schema content and the reference metadata you provide when registering the schema.

  • All external references must be explicitly declared in the references array.
  • Each name in the reference metadata must match the $ref value used in the schema content.
  • The registry does not automatically resolve $ref URIs or fetch schemas from external URLs or file paths.
  • Referenced schemas must be registered in Solace Schema Registry before you register schemas that depend on them.

This ensures all dependencies remain self-contained and validated within the registry, even if external resources are unavailable.

When you use JSON Schema validation, $ref fields must contain valid URIs.

The following example shows a simple schema that uses $ref to reference an external Address schema. The $ref value "Address.json" tells the schema validator where to find the Address definition. When you register this schema with Solace Schema Registry, you must explicitly declare this reference in the registry metadata:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "address": {
      "$ref": "Address.json"
    }
  }
}

The $id Field in JSON Schema

The $id field provides a canonical identifier for a JSON Schema. Understanding how the registry handles this field is important for reference resolution:

  • Optional—You do not need to include $id in your source schema.
  • Auto-generated—If omitted, the registry automatically adds $id in the format {group}:{artifactId}:{version}. For example, a schema in the default group with artifact ID Address and version 1.0.0 receives "$id": "default:Address:1.0.0".
  • Preserved—If you include $id in your source schema, the registry preserves it exactly as provided.
  • No validation at upload time—The registry does not validate the format of manually-specified $id values when you upload the schema.

Solace recommends that if you provide a custom $id value, ensure it is a valid URI according to RFC 3986. A valid URI must begin with a letter and can contain letters, digits, hyphens (-), periods (.), underscores (_), tildes (~), and other RFC 3986-compliant characters. This helps avoid validation issues during schema processing.

Example - Auto-generated $id:

// Source schema uploaded (no $id)
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Address",
  "type": "object",
  "properties": {
    "street": {"type": "string"}
  }
}

// Retrieved from registry ($id added automatically)
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "$id": "default:Address:1.0.0",
  "title": "Address",
  "type": "object",
  "properties": {
    "street": {"type": "string"}
  }
}

Fragment Identifiers in $ref

The fragment identifier (#) in JSON Schema $ref values points to specific locations within a schema.

Whole-Schema References:

For referencing an entire schema, the # fragment is optional. Both formats work identically:

"$ref": "Address.json"      // Recommended - cleaner
"$ref": "Address.json#"     // Also valid

Recommendation: Use "Address.json" (without #) for clarity when referencing entire schemas.

Definition-Specific References:

Use # with a JSON Pointer path to reference specific definitions within a schema:

"$ref": "common.json#/definitions/Address"     // Reference specific definition
"$ref": "types.json#/definitions/primitives/string"  // Reference nested definition

Avro Schema References

Apache Avro uses namespaces and type names to reference other schemas. When a field's type is specified as a fully-qualified name (namespace + name), for example com.example.common.Address, Avro interprets it as a reference to another schema that must be defined elsewhere.

In the following example of an Avro schema reference, the Customer schema references the Address type from the com.example.common namespace. The referenced Address schema must be registered separately in Solace Schema Registry before you can register or use the Customer schema.

{
  "type": "record",
  "name": "Customer",
  "namespace": "com.example.customer",
  "fields": [
    {
      "name": "address",
      "type": "com.example.common.Address"
    }
  ]
}

Behavior in Schema Registry

Avro uses fully qualified type names (namespace.name) to identify references between schemas. When a schema references another Avro type that isn't defined inline, you must register that referenced schema as a separate artifact and declare it in the references array when submitting the parent schema. The reference metadata must include the fully qualified name used in the schema.

For a complete working example of Avro schema references, see Complete Examples.

Using API Endpoints to work with Schemas

Solace Schema Registry provides two different approaches for working with schemas:

  • Creating a new artifact—Use the POST /groups/{groupId}/artifacts endpoint with a request body that includes artifactId, artifactType, and firstVersion. This creates both the artifact and its initial version in a single operation.
  • Adding a version to an existing artifact—Use the POST /groups/{groupId}/artifacts/{artifactId}/versions endpoint with a request body that includes version and content. This adds a new version to an artifact that already exists.

Both approaches use Content-Type: application/json and support schema references. The key difference is that references must be nested inside the content object, not at the top level of the request body.

For more information, see the Solace Schema Registry REST API documentation.

Querying and Viewing References

After creating schemas with references, you can query and view reference information using the REST API or Solace Schema Registry web console.

Viewing References in the Solace Schema Registry Web Console

To view references for an artifact version in the web console:

  1. Navigate to the artifact in the Explore tab.
  2. Click the Versions tab and select a version.
  3. Click the References tab to see all artifacts referenced by this version.
  4. Optionally, click View artifacts that reference this artifact version to see dependent schemas.

For more information about using the web console, see Using Solace Schema Registry Web Console.

Querying References via REST API

You can retrieve reference information for a specific artifact version using the REST API. The registry provides a dedicated endpoint to list all references for a given version. For a complete list of endpoints, see the Solace Schema Registry REST API documentation.

Retrieving References for a Version

To retrieve all references for a specific artifact version, use the following endpoint:

GET /apis/registry/v3/groups/{groupId}/artifacts/{artifactId}/versions/{version}/references

For example, to retrieve references for the Customer artifact version 1.0.0 in the default group:

curl -X GET "http://<MY_REGISTRY_URL>/apis/registry/v3/groups/default/artifacts/Customer/versions/1.0.0/references"

The response returns an array of reference objects:

[
  {
    "groupId": "default",
    "artifactId": "Address",
    "version": "1.0.0",
    "name": "Address.json"
  }
]

Each reference object contains:

  • groupId—The group containing the referenced artifact.
  • artifactId—The unique identifier of the referenced artifact.
  • version—The specific version of the referenced artifact.
  • name—The reference name used in the schema content, this value matches the $ref value for JSON Schema or fully-qualified type name for Avro.

If the artifact version has no references, the endpoint returns an empty array [].

Registry Role in Managing References

Solace Schema Registry actively manages schema references to maintain the integrity of your schema ecosystem. It provides dependency tracking, validation, and protection mechanisms that ensure your schemas remain consistent and reliable.

The registry maintains a complete dependency graph that tracks all relationships between schemas. By maintaining metadata about all schema references, Solace Schema Registry provides the following capabilities:

Reference Validation

When you register a schema with references, Solace Schema Registry performs the following validation at upload time:

  • Verifies that all referenced artifacts exist in the registry.
  • Confirms that the specified versions of referenced artifacts are available.
  • Checks that the reference metadata is properly formatted.

The registry does not validate that the reference name field matches the $ref values in the schema content, nor does it validate schema constraints or data types. This validation occurs later during runtime when the SERDES processes messages with VALIDATE_SCHEMA = true. If any validation check fails at upload time, the registry rejects the schema registration and returns an error describing the problem.

Deletion Protection

Solace Schema Registry prevents deletion of schemas that are referenced by other schemas. This protection ensures that you cannot accidentally break existing schemas by deleting their dependencies.

To delete a schema that is referenced by others, you must first:

  1. Identify all schemas that reference the target schema.
  2. Update or delete those dependent schemas.
  3. Then delete the target schema.

Validation Implications: Schema Storage vs. Validation

Understanding how Solace Schema Registry validates schemas with references is important to avoid runtime errors and ensure data quality. The registry performs different types of validation at different stages:

  • Upload-time validation—When you register a schema, the registry performs some validation. It checks that the schema content is syntactically valid JSON or Avro, but does not validate reference resolution or schema constraints. A schema with incorrect or missing reference metadata can still be successfully registered.
  • Runtime validation (SERDES)—When the SERDES validates data against a schema (with VALIDATE_SCHEMA = true), it must resolve all $ref references and apply all schema constraints. If any referenced schema cannot be resolved or if data violates schema constraints, validation fails.

Because of this two-stage validation, you can successfully register a schema that contains reference issues, but then encounter validation errors when the schema is used to process messages.

Common Validation Failures

Validation failures related to references typically occur when:

  • Missing references—A referenced schema does not exist in the registry.
  • Incorrect version—The specified version of a referenced schema is not available.
  • Mismatched names—The reference name does not match the $ref value (JSON Schema) or fully qualified type name (Avro).
  • Circular dependencies—Two or more schemas reference each other in a loop.

Complete Examples

These examples demonstrate how to create schema artifacts with references for both JSON Schema and Apache Avro, and they include the full workflow: API request structure, reference metadata, and expected responses.. For information about the API endpoints used in these examples, see Using API Endpoints to work with Schemas.

JSON Schema Example

This example demonstrates creating two JSON Schema artifacts where one references the other.

  1. Create the Address Artifact (Without References)—First, create the Address artifact that will be referenced by other schemas. This example shows creating a new artifact without any references:
    curl -X POST "http://<MY_REGISTRY_URL>/apis/registry/v3/groups/default/artifacts" \
      -H "Content-Type: application/json" \
      -d '{
        "artifactId": "Address",
        "artifactType": "JSON",
        "firstVersion": {
          "version": "1.0.0",
          "content": {
            "contentType": "application/json",
            "content": "{\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"Address\",\"type\":\"object\",\"properties\":{\"street\":{\"type\":\"string\",\"description\":\"Street address\"},\"city\":{\"type\":\"string\",\"description\":\"City name\"},\"state\":{\"type\":\"string\",\"description\":\"State or province\"},\"zipCode\":{\"type\":\"string\",\"description\":\"Postal code\"},\"country\":{\"type\":\"string\",\"description\":\"Country name\"}},\"required\":[\"street\",\"city\",\"zipCode\",\"country\"]}"
          }
        }
      }'

    This command creates a JSON Schema artifact named Address in the default group with version 1.0.0. The schema has no dependencies on other schemas.

  2. Create the Customer Artifact with Reference—Next, create the Customer artifact that references the Address artifact. This example demonstrates how to include the references array in the request:
    curl -X POST "http://<MY_REGISTRY_URL>/apis/registry/v3/groups/default/artifacts" \
      -H "Content-Type: application/json" \
      -d '{
        "artifactId": "Customer",
        "artifactType": "JSON",
        "firstVersion": {
          "version": "1.0.0",
          "content": {
            "contentType": "application/json",
            "content": "{\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"Customer\",\"type\":\"object\",\"properties\":{\"customerId\":{\"type\":\"string\",\"description\":\"Unique customer identifier\"},\"name\":{\"type\":\"string\",\"description\":\"Customer full name\"},\"email\":{\"type\":\"string\",\"format\":\"email\",\"description\":\"Customer email address\"},\"billingAddress\":{\"$ref\":\"Address.json\"},\"shippingAddress\":{\"$ref\":\"Address.json\"}},\"required\":[\"customerId\",\"name\",\"email\",\"billingAddress\"]}",
            "references": [
              {
                "groupId": "default",
                "artifactId": "Address",
                "version": "1.0.0",
                "name": "Address.json"
              }
            ]
          }
        }
      }'

    Important details about this request:

    • The Content-Type header is application/json
    • The schema content is provided as a JSON-encoded string in the content.content field
    • The references array is nested inside the content object, not at the top level
    • The name field in the reference (Address.json) matches the $ref value used in the schema content

    The Customer schema references Address twice for billing and shipping addresses, but only one reference entry is needed in the metadata since both $ref statements point to the same artifact. While the registry accepts duplicate reference entries without error, declaring each unique reference only once is cleaner and more maintainable.

    When validation is enabled in your SERDES configuration (VALIDATE_SCHEMA = true), the validator will resolve the Address.json reference and enforce all constraints defined in the Address schema. For example, if the Address schema requires street, city, zipCode, and country fields, validation will fail if any Customer message has a billingAddress or shippingAddress missing any of these required fields. The error message will include the JSON path to the problematic field, for example $.billingAddress: required property 'country' not found.

  3. (Optional) Add a New Version with References—To add a new version to an existing artifact, use the versions endpoint. This example adds version 2.0.0 to the Customer artifact:

    curl -X POST "http://<MY_REGISTRY_URL>/apis/registry/v3/groups/default/artifacts/Customer/versions" \
      -H "Content-Type: application/json" \
      -d '{
        "version": "2.0.0",
        "content": {
          "contentType": "application/json",
          "content": "{\"$schema\":\"http://json-schema.org/draft-07/schema#\",\"title\":\"Customer\",\"type\":\"object\",\"properties\":{\"customerId\":{\"type\":\"string\",\"description\":\"Unique customer identifier\"},\"name\":{\"type\":\"string\",\"description\":\"Customer full name\"},\"email\":{\"type\":\"string\",\"format\":\"email\",\"description\":\"Customer email address\"},\"phone\":{\"type\":\"string\",\"description\":\"Customer phone number\"},\"billingAddress\":{\"$ref\":\"Address.json\"},\"shippingAddress\":{\"$ref\":\"Address.json\"}},\"required\":[\"customerId\",\"name\",\"email\",\"billingAddress\"]}",
          "references": [
            {
              "groupId": "default",
              "artifactId": "Address",
              "version": "1.0.0",
              "name": "Address.json"
            }
          ]
        }
      }'

    This adds version 2.0.0 to the Customer artifact, which includes a new phone field while maintaining the same reference to the Address artifact. Note that the references array is still nested inside the content object.

Apache Avro Example

This example demonstrates creating two Avro schema artifacts where one references the other using namespaces.

  1. Create the Status Enum Artifact—First, create a simple enum artifact that will be referenced:

    curl -X POST "http://<MY_REGISTRY_URL>/apis/registry/v3/groups/default/artifacts" \
      -H "Content-Type: application/json" \
      -d '{
        "artifactId": "Status",
        "artifactType": "AVRO",
        "firstVersion": {
          "version": "1.0.0",
          "content": {
            "contentType": "application/json",
            "content": "{\"type\":\"enum\",\"name\":\"Status\",\"namespace\":\"com.example.common\",\"doc\":\"Order status enumeration\",\"symbols\":[\"PENDING\",\"CONFIRMED\",\"SHIPPED\",\"DELIVERED\",\"CANCELLED\"]}"
          }
        }
      }'
  2. Create the Order Artifact with Reference—Create the Order artifact that references the Status enum:
    curl -X POST "http://<MY_REGISTRY_URL>/apis/registry/v3/groups/default/artifacts" \
      -H "Content-Type: application/json" \
      -d '{
        "artifactId": "Order",
        "artifactType": "AVRO",
        "firstVersion": {
          "version": "1.0.0",
          "content": {
            "contentType": "application/json",
            "content": "{\"type\":\"record\",\"name\":\"Order\",\"namespace\":\"com.example.orders\",\"doc\":\"Order record\",\"fields\":[{\"name\":\"orderId\",\"type\":\"string\",\"doc\":\"Unique order identifier\"},{\"name\":\"customerId\",\"type\":\"string\",\"doc\":\"Customer identifier\"},{\"name\":\"orderDate\",\"type\":\"long\",\"doc\":\"Order timestamp in milliseconds\"},{\"name\":\"totalAmount\",\"type\":\"double\",\"doc\":\"Total order amount\"},{\"name\":\"status\",\"type\":\"com.example.common.Status\",\"doc\":\"Current order status\"}]}",
            "references": [
              {
                "groupId": "default",
                "artifactId": "Status",
                "version": "1.0.0",
                "name": "com.example.common.Status"
              }
            ]
          }
        }
      }'

    Note that the name field in the reference matches the fully-qualified type name used in the status field of the Order schema.

  3. (Optional) Add a New Version with References—To add a new version to the existing Order artifact:
    curl -X POST "http://<MY_REGISTRY_URL>/apis/registry/v3/groups/default/artifacts/Order/versions" \
      -H "Content-Type: application/json" \
      -d '{
        "version": "2.0.0",
        "content": {
          "contentType": "application/json",
          "content": "{\"type\":\"record\",\"name\":\"Order\",\"namespace\":\"com.example.orders\",\"doc\":\"Order record\",\"fields\":[{\"name\":\"orderId\",\"type\":\"string\",\"doc\":\"Unique order identifier\"},{\"name\":\"customerId\",\"type\":\"string\",\"doc\":\"Customer identifier\"},{\"name\":\"orderDate\",\"type\":\"long\",\"doc\":\"Order timestamp in milliseconds\"},{\"name\":\"totalAmount\",\"type\":\"double\",\"doc\":\"Total order amount\"},{\"name\":\"priority\",\"type\":\"string\",\"doc\":\"Order priority level\",\"default\":\"NORMAL\"},{\"name\":\"status\",\"type\":\"com.example.common.Status\",\"doc\":\"Current order status\"}]}",
          "references": [
            {
              "groupId": "default",
              "artifactId": "Status",
              "version": "1.0.0",
              "name": "com.example.common.Status"
            }
          ]
        }
      }'

    This adds version 2.0.0 to the Order artifact, which includes a new priority field while maintaining the same reference to the Status artifact.