jsonschema

How is the $id resolved for JSON Schema 2020-12 when there is a relative nested $id?


I'm looking at one of the JSON Schema $anchor tests from https://github.com/json-schema-org/JSON-Schema-Test-Suite/blob/main/tests/draft2020-12/anchor.json and I don't understand how the $ref is supposed to resolve to the "B" object definition.

In the test below the outer $id is set to http://localhost:1234/draft2020-12/root with the inner $id set to nested.json. So shouldn't the fully resolved URI for the inner $id be set to http://localhost:1234/draft2020-12/root/nested.json?

According to the tests, it looks like the inner $id should resolve to http://localhost:1234/draft2020-12/nested.json, taking out the root from the path.

{
    "description": "Location-independent identifier with base URI change in subschema",
    "schema": {
        "$schema": "https://json-schema.org/draft/2020-12/schema",
        "$id": "http://localhost:1234/draft2020-12/root",
        "$ref": "http://localhost:1234/draft2020-12/nested.json#foo",
        "$defs": {
            "A": {
                "$id": "nested.json",
                "$defs": {
                    "B": {
                        "$anchor": "foo",
                        "type": "integer"
                    }
                }
            }
        }
    },
    "tests": [
        {
            "data": 1,
            "description": "match",
            "valid": true
        },
        {
            "data": "a",
            "description": "mismatch",
            "valid": false
        }
    ]
}

Solution

  • RFC3986#Section-5.2.3

    return a string consisting of the reference's path component appended to all but the last segment of the base URI's path (i.e., excluding any characters after the right-most "/" in the base URI path, or excluding the entire base URI path if it does not contain any "/" characters).


    The baseUri for this schema is http://localhost:1234/draft2020-12/root

    The $id of nested.json is considered a relative-path reference because it does not contain a scheme, nor does it begin with // or /. It is resolved against the base uri of the entry point, which is the enclosing schema excluding any characters after the right-most / in the base URI path, http://localhost:1234/draft2020-12/ following the rule outlined above.

    The final piece is the plain fragment in the $anchor keyword, foo.

    src: https://json-schema.org/draft/2020-12/json-schema-core#section-8.2.2-6

    Note that the anchor string does not include the "#" character, as it is not a URI-reference. An "$anchor": "foo" becomes the fragment "#foo" when used in a URI.

    Thus, the plain fragment is resolved against the base uri of the enclosing schema, nested.json#foo which is then resolved against the base uri of the enclosing schema http://localhost:1234/draft2020-12/nested.json#foo