$ref and fragments

137 views
Skip to first unread message

pete hug

unread,
Feb 20, 2014, 3:06:25 AM2/20/14
to json-...@googlegroups.com
I'm confused as to what exactly the purpose is of the fragment separator in URIs.

Consider this schema:

{
 "$schema": "
http://json-schema.org/draft-04/schema#",
 "id": "
http://localhost/customer#",
 "description": "Customer",
 "type": "object",
 "properties": {
  "name": { "type": "string" },
  "addresses": {
   "type": "array",
   "items": { "$ref": "#/definitions/address" }
  }
 },
 "required": ["name", "addresses"],
 "definitions": {
  "address": {
   "type" : "object",
   "properties": {
     "street": { "type": "string" },
     "number": { "type": "string" },
     "suburb": { "type": "string" },
     "city": { "type": "string" },
     "postcode": { "type": "integer" }
   }
  }
 }
}

I see these trailing # in id values for schemas in many, but not all examples and have not found any explanation for it. Surly the base URI for the above schema is http://localhost/customer not http://localhost/customer#, right?

And with regards to definitions should "$ref" : "http://localhost/customer#/definitions/address" give me the schema for address in other schemas?

pete hug

unread,
Feb 20, 2014, 3:09:15 AM2/20/14
to json-...@googlegroups.com
Actually I understand what the purpose is of the fragment separator in URIs, I just don't understand what the purpose is of appending it to the id of a schema.

Francis Galiegue

unread,
Feb 20, 2014, 4:33:07 AM2/20/14
to json-...@googlegroups.com
This is because the URI is a JSON Reference. In a JSON Reference, the
fragment part is supposed to be a (URI-encoded) JSON Pointer.

And no fragment, or an empty JSON Pointer, are the same. The URI with
an empty fragment is the "canonicalized" form of the JSON Reference,
if you prefer.

--
Francis Galiegue, fgal...@gmail.com
JSON Schema in Java: http://json-schema-validator.herokuapp.com

Francis Galiegue

unread,
Feb 20, 2014, 4:37:40 AM2/20/14
to json-...@googlegroups.com
Also (sorry, I didn't see that part of the question initially):

On Thu, Feb 20, 2014 at 9:06 AM, pete hug <huggy...@gmail.com> wrote:
[...]
>
> And with regards to definitions should "$ref" :
> "http://localhost/customer#/definitions/address" give me the schema for
> address in other schemas?
>

It allows you to address a subschema, yes. The steps are first to find
the schema for http://localhost/customer# (see my previous mail), and
then resolve JSON Pointer "/definitions/address" within the schema you
found.

As a side note, this is a bizarre URI to use as localhost will almost
certainly resolve to the local machine, so this is not really
"portable"...

pete hug

unread,
Feb 20, 2014, 3:47:19 PM2/20/14
to json-...@googlegroups.com
Thanks Francis.

I'm still a bit confused with these fragments...

If I retrieve a JSON document that returns the Link header http://localhost/customer; rel="describedby", but the schema itself specifies an "id": "http://localhost/customer#" I have a problem. Before I retrieve the schema, I'd try to find http://localhost/customer in my schema cache, and if I don't find it, I'd retrieve the schema from the specified location and cache it using its id value as key (including the appended fragment separator). IOW, the next time I receive said Link header, I do another server round trip to retrieve something I already have in my cache.

From that I naturally follow that I need to remove fragment separators with an empty JSON Pointer. But now I no longer understand why anybody would specify an id like http://localhost/customer# instead of http://localhost/customer?


I also question that fragments are followed by a JSON Pointer notion. Lets add and "id" value to definitions/address with value "#address" to my original sample:

#",

 "description": "Customer",
 "type": "object",
 "properties": {
  "name": { "type": "string" },
  "address": { "$ref": "#/definitions/address" }

 },
 "required": ["name", "addresses"],
 "definitions": {
  "address": {
   "id" : "#address",
   "type" : "object",
   "properties": {
     "street": { "type": "string" },
     "number": { "type": "string" },
     "suburb": { "type": "string" },
     "city": { "type": "string" },
     "postcode": { "type": "integer" }
   }
  }
 }
}

Could I not now reference the definition of address from this schema in other schemas with http://localhost/customer#address?

If I understand the specs correctly, #definitions/address is a JSON pointer and a valid reference I could use, but so is #address which is not a JSON pointer but an in-lined schema id. If my interpretation is correct, than this could lead to ambiguities unless the resolution is always in-lined before JSON pointer resolution.

Did I miss this part in the specs?

Francis Galiegue

unread,
Feb 21, 2014, 2:08:32 AM2/21/14
to json-...@googlegroups.com
Hello again,

On Thu, Feb 20, 2014 at 9:47 PM, pete hug <huggy...@gmail.com> wrote:
[...]
>
> I'm still a bit confused with these fragments...
>
> If I retrieve a JSON document that returns the Link header
> http://localhost/customer; rel="describedby", but the schema itself
> specifies an "id": "http://localhost/customer#" I have a problem. Before I
> retrieve the schema, I'd try to find http://localhost/customer in my schema
> cache, and if I don't find it, I'd retrieve the schema from the specified
> location and cache it using its id value as key (including the appended
> fragment separator). IOW, the next time I receive said Link header, I do
> another server round trip to retrieve something I already have in my cache.
>

Well, this is why in my JsonRef class, I have a .getLocator() method
which returns the URI _without_ the fragment part ;) This way I can
avoid "checking out" the schema twice.

> From that I naturally follow that I need to remove fragment separators with
> an empty JSON Pointer. But now I no longer understand why anybody would
> specify an id like http://localhost/customer# instead of
> http://localhost/customer?
>

Again, because this is a JSON Reference and the canonical form of a
JSON Reference is a base URI followed by a JSON Pointer fragment.

>
> I also question that fragments are followed by a JSON Pointer notion. Lets
> add and "id" value to definitions/address with value "#address" to my
> original sample:
>

[...]

Yes, this is unfortunately the case that JSON Schema has to "extend"
upon JSON Reference to allow arbitrary fragments. I wished it removed
but I was alone in that...

> {
> "$schema": "http://json-schema.org/draft-04/schema#",
> "id": "http://localhost/customer
> #",
>
> "description": "Customer",
> "type": "object",
> "properties": {
> "name": { "type": "string" },
> "address": { "$ref": "#/definitions/address" }
>
> },
> "required": ["name", "addresses"],
> "definitions": {
> "address": {
> "id" : "#address",
> "type" : "object",
> "properties": {
> "street": { "type": "string" },
> "number": { "type": "string" },
> "suburb": { "type": "string" },
> "city": { "type": "string" },
> "postcode": { "type": "integer" }
> }
> }
> }
> }
>
> Could I not now reference the definition of address from this schema in
> other schemas with http://localhost/customer#address?
>

Spot on... The only answer I can give here is "I don't know". My
implementation _does_ reference this correctly, no idea for others.

Using JSON Pointers as fragment parts, however, removes the ambiguity!

> If I understand the specs correctly, #definitions/address is a JSON pointer
> and a valid reference I could use, but so is #address which is not a JSON
> pointer but an in-lined schema id. If my interpretation is correct, than
> this could lead to ambiguities unless the resolution is always in-lined
> before JSON pointer resolution.
>
> Did I miss this part in the specs?
>

No you didn't. This is indeed a source of potential problems, which I
have fought to be solved but never got to solve.

Yes, I still want non JSON Pointer fragments removed from the spec.
And yes, I am the only one who wants that :(
Reply all
Reply to author
Forward
0 new messages