1

JSON-Schema-Test-Suite defines schemas such as this, and I assume they are valid:

{
    "tilda~field": {"type": "integer"},
    "slash/field": {"type": "integer"},
    "percent%field": {"type": "integer"},
    "properties": {
        "tilda": {"$ref": "#/tilda~0field"},
        "slash": {"$ref": "#/slash~1field"},
        "percent": {"$ref": "#/percent%25field"}
    }
}

Take this example below:

{
    "$id": "http://example.com/root.json",
    "definitions": {
        "A": { "type": "integer" }
    },
    "properties": {
        "$id": {
            "type": "string"
        },
        "attributes": {
            "$ref": "#/tilda~0field/slash~1field/$id"
        }
    },
    "tilda~field": {
        "$id": "t/inner.json",
        "slash/field": {
            "$id": {
                "$id": "test/b",
                "$ref": "document.json"
            }
        }
    }
}

Which of the following is the $ref at #/tilda~0field/slash~1field/$id/$ref resolved to?

Which of the $ids in #/tilda~0field must be considered as baseURI for the $ref in question and why.

aravindanve
  • 979
  • 7
  • 14

3 Answers3

3

$refs are not resolved within unknown keywords because $ref and $id only apply inside schemas. Let's look at an example to see what I mean by this.

{
  "$id": "http://example.com/foo",
  "type": "object",
  "properties": {
    "aaa": {
      "const": { "$ref": "#/definitions/bbb" }
    },
    "bbb": { "$ref": "#/definitions/bbb" }
  },
  "ccc": { "$ref": "#/definitions/bbb" },
  "definitions": {
    "bbb": { "type": "string" }
  }
}
  • The document as a whole is a schema, so /$id is understood by JSON Schema.
  • The properties keyword is defined as an object whose values are schemas. Therefore, the value at /properties/bbb is a schema and /properties/bbb/$ref is understood by JSON Schema.
  • The value of the const keyword is unconstrained. The value at /properties/aaa/const may look like a schema, but it's just a plain JSON object. Therefore /properties/aaa/const/$ref is not understood by JSON Schema.
  • The value at /ccc is not a JSON Schema keyword, so it's value is not constrained and not a schema. Therefore, the $id and $ref keywords are not understood by JSON Schema.

That's how it works now. When you go back to older drafts (draft-05 iirc), it's a little different. Before then, $ref was defined in a separate specification called JSON Reference. JSON Schema extended JSON Reference. Therefore, the semantics of $ref applied everywhere it appeared in a JSON Schema.

EDIT:

What happens when a $ref inside a known keyword references a schema deep inside an unknown keyword. for example, what if #/properties/bbb referenced #/ccc?

That's a really good question. Referencing #/ccc should be an error because #/ccc is not a schema and $ref only allows you to reference a schema.

Jason Desrosiers
  • 22,479
  • 5
  • 47
  • 53
  • wow. answered at the same time, says the same thing, yet yours is somehow better. ;-) – gregsdennis Dec 02 '18 at 06:44
  • @jason-desrosiers when you say `$refs are not resolved within unknown keywords because $ref and $id only apply inside schemas.` What happens when a `$ref` inside a known keyword references a schema deep inside an unknown keyword. for example, what if `#/properties/bbb` referenced `#/ccc`. – aravindanve Dec 02 '18 at 07:49
  • I kinda jumped the gun and posted this in two places, can you please take a look at my comment here: https://github.com/json-schema-org/json-schema-spec/issues/687#issuecomment-443489995 – aravindanve Dec 02 '18 at 08:19
  • @AravindanVe, I edited the answer to answer your question. – Jason Desrosiers Dec 02 '18 at 17:00
  • Oh thanks! That answers by question. But there is also the case of the tests. i.e. JSON-Schema-Test-Suite defines many test cases that routinely reference unknown parts of the schema, like in the first example. – aravindanve Dec 02 '18 at 18:51
  • 1
    I think the test suite is wrong. I don't think the spec authors recognized this problem when they added the restriction that you can only reference schemas. I certainly haven't thought about this case til you brought it up. – Jason Desrosiers Dec 02 '18 at 18:57
1

I just saw your question on the JSON Schema site in an issue. I'll post here what I posted there as well. However, also look at the edit.


Which of the following is the $ref at #/tilda~0field/slash~1field/$id/$ref resolved to?

I think Section 8.2 gives the answer: "A subschema's "$id" is resolved against the base URI of its parent schema." This means that it will be http://example.com/t/test/document.json.

Which of the $ids in #/tilda~0field must be considered as baseURI for the $ref in question and why.

The base URI for this is the $id at the root, re-routed by the $id in tilda~field.

  1. Start with http://example.com/root.json.
  2. Change folders to t and use file inner.json.
  3. Change folders to test (inside t) and use file document.json.

EDIT

Having a look at @customcommander's reply and realizing that the value in tilde~field isn't processed as a schema, I'd like to say that the #ref wouldn't be processed at all. It's just a plain JSON string with no inherent meaning.

gregsdennis
  • 7,218
  • 3
  • 38
  • 71
0

Are you sure your second schema is valid though?

For example according to the JSON Schema Core specification, the $id property should be a string

If present, the value for this keyword MUST be a string

Therefore the following looks wrong to me:

"slash/field": {
  "$id": {
      "$id": "test/b",
      "$ref": "document.json"
  }
}

Then I think that your first $ref isn't correct either:

"attributes": {
  "$ref": "#/tilda~0field/slash~1field/$id"
}

It should probably read:

"attributes": {
  "$ref": "#/tilda~0field/slash~1field"
}

The same specification document also says this about $id and $ref: Cf this example

The "$id" keyword defines a URI for the schema, and the base URI that other URI references within the schema are resolved against.

Or as Ajv simply puts it:

$ref is resolved as the uri-reference using schema $id as the base URI […].

Given the current state of your schema, I can only approximate the answer to your question but the ref would probably resolve to something like t/inner.json#document.json

customcommander
  • 17,580
  • 5
  • 58
  • 84
  • 1
    The `$id` property of `slash/field` as an object is fine since `tilde~field` isn't a recognized keyword. The spec says to treat such things as miscellaneous data and ignore it. Thus references into the JSON structure here *could* work normally. – gregsdennis Dec 02 '18 at 05:53