user2296277
user2296277

Reputation: 25

How can I reference an inner object defined in another schema without explicitly specifying the whole path

I have the following files:

A.json

{
  "B": {
    "level1": {
      "abc": "123"
    }
  }
}

ASchema.json

{
  "$id": "ASchema.json",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "properties": {
    "B": {
      "allOf": [
        {
          "$ref": "BSchema.json#/definitions/B"
        },
        {
          "properties": {
            "level1": {
              "properties": {
                "abc": {
                  "enum": [
                    "123"
                  ]
                }
              }
            }
          }
        }
      ]
    }
  },
  "type": "object"
}

BSchema.json

{
  "$id": "BSchema.json",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "definitions": {
    "B": {
      "$id": "#/definitions/B",
      "type": "object",
      "required": [
        "level1"
      ],
      "properties": {
        "level1": {
          "$id": "#/definitions/B/properties/level1",
          "type": "object",
          "required": [
            "abc"
          ],
          "properties": {
            "abc": {
              "$id": "#/definitions/B/properties/level1/properties/abc",
              "type": "string"
            }
          }
        }
      }
    }
  }
}

I would like to add a constraint for the inner object (B.level1.abc in BSchema.json) in ASchema.json without explicitly typing out the full path as I have done in the example above:

"properties": {
  "level1": {
    "properties": {
      "abc": {
        "enum": [
          "123"
        ]
      }
    }
  }
}

Is there a way to reference the inner object via its id? Something similar to:

{
  "$ref": {
    "BSchema.json#/definitions/B/properties/level1/properties/abc",
    "enum": [ "123" ]
  }
}

Upvotes: 1

Views: 329

Answers (1)

Relequestual
Relequestual

Reputation: 12315

After discussion on slack, I understand your question a lot clearer. You want to be able to reference a part of another schema directly without needing the full path.

To do that using JSON Schema draft-7, you must use a named $id. Here's a simplified example and live demo.

{
  "$id": "http://example.com/ASchema.json",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "definitions": {
    "B": {
      "$id": "http://example.com/BSchema.json",
      "type": "object",
      "required": [
        "level1"
      ],
      "properties": {
        "level1": {
          "$id": "#level",
          "allOf": [false]
        }
      }
    }
  },
  "allOf": [
    {
      "$ref": "BSchema.json#level"
    }
  ]
}

Let me explain what's happening in this schema.

I have simplified your example by in-lining (or transcluding) BSchema into a definition. It doesn't matter what that definition is keyed by for this example, just that it's in a valid subschema location.

The subschema has a FULL URI $id of http://example.com/BSchema.json. This resets the base URI when evaluating an subschemas in that tree.

In BSchema properties, we define level1 as having an $id of `#level'. This is like the id attribute in an HTML element.

To simplify the example, level1 is simply set to false to make the schema fail validation for the demo.

After the definitions, we reference BSchema.json#level. Note not "level1", so that property name can change.

Resolution happens by, looking at the base URI for the schema, which in this case is the root schema, and using URI resolution rules to determine the correct URI http://example.com/BSchema.json. Next the fragment of the URI is the target, and is found in the BSchema schema.

Upvotes: 1

Related Questions