-
-
Notifications
You must be signed in to change notification settings - Fork 290
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Resolving $refs defined in unknown keywords #687
Comments
$ref
s defined in unknown keywords
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.
The base URI for this is the
This is a perfect place to post questions. It's watched and it will be available for other to read. If you want to carry on in conversation "offline" about something, then feel free to join the Slack workspace. |
I think this answer is better than what I said, though the gist of it is the same. |
Thanks for the prompt response @gregsdennis!
The problem is, I'm not clear on how to identify the last parent schema. The spec says:
So if a schema defines an unknown keyword {
"$id": "http://example.com/root.json",
"properties": {
"required": ["$id"],
"$id": { "type": "string" },
"$name": { "type": "string" },
"$email": { "type": "string", "format": "email" },
"$title": {
"$ref": "#/mappings/$title"
},
"$profile": {
"$ref": "#/mappings/$profile"
}
},
"mappings": {
"$id": "_id",
"$name": "name",
"$title": {
"$ref": "title.json"
},
"$profile": {
"$ref": "profile.json"
}
}
} Now, when my validator encounters Resolving the $ref If it has to resolve the But Should it use PS I understand in both cases the ref resolves to |
@aravindanve, that's a really good question. I doubt anyone considered a case like that when this was defined. I certainly haven't.
If you could |
The interesting question here is, how does this affect custom keywords? How does it affect vocabularies? |
The key lies in the "SHOULD be ignored" portion. Just ignore it as miscellaneous data. It's not invalid to have it there, but neither should your implementation do anything with it, except maybe store it for serialization back into JSON. Don't throw; don't resolve the references. It's just JSON data. In regard to vocabularies, a draft-08 concept, supposing a vocabulary was declared that defines |
@jdesrosiers @gregsdennis This clears things up. But you see, my first example:
Is lifted directly from JSON-Schema-Test-Suite. I think there are a bunch of tests that routinely reference schemas nested inside unknown keywords. For now, in my implementation I'll disallow |
@jdesrosiers One other thing
Technically So when you say "you can not $ref those paths because $ref is only allowed to reference a schema", it is referencing a schema :) |
@gregsdennis What do you mean by:
If i dont resolve the reference in |
Every time I look at this my brain First, since the original reference (which is processed by the implementation as it's under the Second, the schema at To confuse things even more, if you were to wrap the By "Don't throw; don't resolve the references," I was just saying that the implementation should ignore the contents of the data. On its own, the contents of unknown keywords shouldn't be validated and references contained within the data shouldn't be resolved. But in your case, the resolution journey begins within a known keyword, so continued resolution is expected. |
@aravindanve @gregsdennis 's explanations are correct.
So that test suite example is fine. It would be nice to make it a bit less confusing but if you want to argue for that please file that on the test suite repository. |
@gregsdennis @handrews I can see what the tests are getting at. I can see the utility in allowing such purely location based references. But my point is, it introduces a certain level of ambiguity as those unknown keyword object references go deeper and deeper. Okay, so for now i'll stick to this:
I'll resolve all Because the alternative is to determine the nearest parent that "fits" the definition of a schema and use its Thanks & Cheers! |
In my interpretation, you don't, because {$ref} is only parsed where a schema is expected, and that is not a place where a schema is expected. |
@awwright on its own, correct, this is not a place where a schema is expected. However, the example shows a |
@gregsdennis Got it. The conclusion of my point is don't author schemas like that, instead put schema definitions under a "definitions" block where the schema is expected. But for schema authors who insist, I think implementations should use whatever URI was used to look up the schema. (This is the standard RFC3986 behavior). This suggests ignoring parent schemas. |
This seems important enough to say again. |
@awwright hmm... maybe there's something worth clarifying here. I think the confusion can be summarized with: {
"$schema": "https://json-schema.org/draft-08",
"$id": "https://example.com/whatever",
"properties": {
"a": {"$ref": "#/$defs/foo/thisKeywordIsUnknown/alsoUnknown/aDef"}
},
"$defs": {
"foo": {
"$id": "foo",
"thisKeywordIsUnknown": {
"$id": "bar",
"alsoUnknown": {
"aDef": {"$ref": "#target"}
}
}
}
}
} What is the resolved URI that ends with Since But we don't know how to interpret the "$id" in the object at So I think the reference unltimately resolves to |
@handrews Good example, if I'm fixing the typo in your $ref correctly. Is this significantly different than this one? {
"$schema": "https://json-schema.org/draft-08",
"$id": "https://example.com/whatever",
"properties": {
"a": {"$ref": "#/$defs/foo/$defs/aDef"}
},
"$defs": {
"foo": {
"$id": "foo",
"$defs": {
"aDef": {"$ref": "#target"}
}
}
}
} That is, if we're using property paths in fragments to identify a schema, think the same behavior I'm talking about still applies; even when we are pointing to a schema where a schema is expected. |
Your missing the point.
That's the way I've always thought about it, but this issue has made me realize that that's not what the spec says. When the spec was changed to only allow
As true as this is, it's skirting the issue. Validator implementers need clear and consistent rules to build their tools. I feel like people keep bringing up real issues with using |
Which part of the spec says this? draft-7 8.3 says " Chagelog for draft-wright-json-schema-00 does say
But I don't see how, or at least, it's not explicit enough if that was the intent. I think I agree that it's currently ambigious. |
While it's not very explicit, there's this requirement:
and there's no other provision for a "$ref" property to be interpreted as a reference outside of a schema. |
@awwright I think you've missed the point here! Say I have a json instance that has $schema and $id at the top level, and no other schema key words... but nested in non schema keywords is a valid JSON Schema. If another file references the $id in the first schema, and includes the path to the child object which is a valid schema, should that referenced JSON object then be considered a valid schema, even though in the first schema it has no implications (as it isn't in a place you'd expect to find a schema). If THAT schema then has a $ref... when it's in the first schema file, it is never looked at, because it's nested under unrecognised keywords, however when evaluated by the second schema file, assuming the JSON object is now treated as a valid JSON Schema, the $ref is now in a location where you'd expect to find a schema. |
I think that's pretty clear.
This on the other hand, says something different. If this was the way it was defined in the spec, it would be more consistent with the intended behavior. |
Agreed. Having a But if you skip validation against the meta-schema,
The current spec presents So while the current draft does not explicitly say "you cannot use |
But, didn't this issue bring to our attention that that isn't true?
I'm pretty sure that was referring to no longer allowing something like the following. {
"type": "string",
"minLength": 3,
"maxLength": { "$ref": "#/minLength" }
} We made the decision to limit JSON Reference to only be allowed where a schema is expected. The wording in the changelog wording describes the intended behavior accurately while the spec wording does not because the changelog limits the source while the spec limits the target. |
@jdesrosiers I guess I failed to explain the difference between "conceptually the same" which was intended to capture the original intuition, and "mechanically the same" which would address how things actually work (or don't work). Regarding:
that was a bad edit/sentence construction on my part. It was supposed to be something like:
I tend to rewrite these things a lot and sometimes splice ideas by accident. Regardless, the current spec says what it intends to say, which is different from that changelog from four drafts ago. |
@aravindanve @jdesrosiers @gregsdennis my inclination is to state something like this:
That's a little awkward, but perhaps we can figure out a way to be more clear. It's basically what @awwright meant with "don't do that", but written up in standards-ese 😁 ("undefined behavior" is standards-ese for "don't do that") Would this work, at least to get draft-08 out the door? |
How should a json-schema (draft7) implementation resolve
$ref
s defined in unknown keywords?JSON-Schema-Test-Suite defines schemas such as this, and I assume they are valid:
Take this example below:
Which of the following is the
$ref
at#/tilda~0field/slash~1field/$id/$ref
resolved to?Which of the
$id
s in#/tilda~0field
must be considered as baseURI for the$ref
in question and why.PS I'm not sure if this is the right place to post this. If I need to clarify further or post this elsewhere, please let me know.
The text was updated successfully, but these errors were encountered: