RE: Inheritance / composition of term definitions

On Wednesday, November 25, 2015 6:40 PM, Dietrich Schulten wrote:
> On 19 Nov 2015 at 17:19, Lukas Graf wrote:
>> I’m currently involved in designing and implementing a REST API for a CMS (Plone) that
>> is supposed to eventually be hypermedia driven, using JSON-LD and Hydra.

Very cool! I'm already looking forward to see the first prototype.


>> Currently I’m still in the process of wrapping my head around all these exciting new
>> concepts, and navigating the available specs, so please bear with me if I get some of the
>> terminology or even fundamental ideas wrong.

It's probably rather us that need you to ask you to bear with us till we get the specs and everything in a better shape :-)
Keep the questions coming.. usually you also get answers much quicker.


>> On a most basic level, our CMS makes a distinction between contentish types and folderish
>> types (Items and Containers if you will). The CMS supports user-defined content types with
>> their own schema, so JSON-LD contexts for those will need to be generated dynamically by
>> the API.

Not necessarily. You can use @vocab [1] to automatically map all non-otherwise mapped properties. But it obviously depends on what exactly you need.


>> We’re now discussing how to expose parent/children relationships (mainly for relationships
>> that imply containment, but much of this could also be applied to dynamic collections or
>> references I assume). So currently we’re considering using the "member" term defined by
>> Hydra to represent children of a container, or members of a collection.

That's what is has been made for


>> However, if we simply use the term "member", there’s a potential name
>> conflict if a content type already defines a "member" attribute. That
>> could be avoided by namespacing, in the sense that we stick the metadata
>> of the objects that are being exposed into their own JSON object.
>> 
>> But, in order to cater to clients that don’t know anything about JSON-LD, I’d like to keep
>> the exposed data structures simple and somewhat expressive even without the additional
>> context provided by linked data. That means, I’d like to avoid unnecessarily nesting the
>> metadata of our exposed objects in deep structures - the primary attributes should be at the
>> top level of the data structure.

+1

 
>> If possible, I’d also like to be able to keep attribute names as defined in the domain specific
>> model - meaning, I’d like to name the list of users in a group "users", participants of a
>> meeting "participants", etc., instead of naming them all "member".

Why would you want to switch to a generic container type such as Hydra's Collection then?
 

>> Let me provide an example to hopefully help make this question less abstract:
>> 
>> {
>>    "@context": "http://example.org/",
>>    "@type": "Building",
>>    "@id":"http://example.org/buildings/main",
>>    "name":"Main Building",
>>    "address": "...",
>>    "rooms": [
>>       {
>>          "@type":"Room",
>>          "@id":"http://example.org/buildings/main/lobby",
>>          "name":"Lobby"
>>       },
>>       {
>>          "@type":"Room",
>>          "@id":"http://example.org/buildings/main/blue-room",
>>          "name":"Blue Room"
>>       }
>>    ]
>> }
>> 
>> Here the folderish type "Building" has an attribute "rooms" which is a list of "Room" objects
>> contained in that building.
>> 
>> Ideally, my goal woud be to:
>> 
>> - Keep the name "rooms" (instead of "member"), as that's would be the
>> attribute name used in the content types data model, which API consumers
>> would be familiar with
> 
> Perfectly possible, as long as there is no need to address the rooms
> as a resource, with its own url that resolves to a collection of
> rooms.

Exactly. The collection would sit between the building and the room in this example. Do you need that?


>> - Have the term be part of the domain specific JSON-LD context
[...]
>> - Still associate the "rooms" term with "hydra:member",
>> so that Hydra capable clients have the necessary information to figure
>> out that the "rooms" property contains the collection members

What would they gain by that? Do you want to allow users to filter the rooms for example?
You could definitely make the "rooms" property a sub-property of hydra:member but for that to be useful we would need to require all clients understand such things.


> The hydra:member attribute belongs on a hydra:Collection. A
> hydra:Collection is mainly useful in situations where you need to
> address a collection resource with a single URl, e.g. because you want
> to POST to it or to offer a UriTemplate to search the collection. The
> new collection construct in the working group wiki, which is not in
> the spec yet, shows how this works:
> 
>    "@context":"http://example.org/", 
>    "@type":"Building", 
>    "@id":"http://example.org/buildings/main", 
>    "name":"Main Building", 
>    "address": "...", 
>     "hydra:collection" : [{
>       "@id":"/rooms",
>       "hydra:operation" : ... 
>        "hydra:manages" : {
>            "hydra:subject" : "/buildings/main", 
>             "hydra:property" : "rooms" 
>        } 
>       "hydra:member":[ 
>         { 
>          "@type":"Room", 
>          "@id":"http://example.org/buildings/main/lobby", 
>          "name":"Lobby" 
>         }, 
>         { 
>          "@type":"Room", 
>          "@id":"http://example.org/buildings/main/blue-room", 
>          "name":"Blue Room" 
>         } 
>      ] 
>    }] 
> } 
> 
> The new Collection has a "manages" attribute which allows to say that
> the items are rooms of the building.

Yep, that could be used as well. But given that these will be custom vocabularies AFAICT, it would be much easier to simply point "rooms" to the collection of rooms instead of individual rooms.


>> - Not having to move the "name" and "address" properties into their own
>> sub-object
> 
> In the example above you don't, why would you need to?
>> 
>> So, from what I understand I could define the base context (?) as my domain specific
>> context (http://example.org/), and add a local context that only redefines the "rooms" term:
>> 
>> {
>>   "@context": [
>>     "http://example.org/",
>>     {
>>       "hydra": "http://www.w3.org/ns/hydra/context.jsonld",
>>       "rooms": "hydra:member"
>>     }
>>   ],
>>   // ...
>> }

Right

 
> Three contexts, two external ones, and a local one:
> 
> "@context": [ 
>     "http://example.org/context.jsonld", 
>      "http://www.w3.org/ns/hydra/context.jsonld", 
>     { 
>       "rooms": "hydra:member" 
>      } 
> ]
> 
> ... assuming that the external base context is not returned at the
> root of example.org, but as a resource context.jsonld below it, and
> that resource is expected to return a context. If you just want to
> define a default prefix for all attributes without prefix, you want
> @vocab within the local context. I would expect rooms to be mapped to
> a URL like http://example.org/vocab#rooms in your domain specific
> context.
>
>> But that would mean that the "rooms" term is now *only* defined as
>> "hydra:member" - if I had a definition in the http://example.org/
>> context for it, that one is now overridden by the local context,
>> correct?
> 
> Last one wins. 

Yes, correct. You can't map a single term/property to multiple IRIs.


>> So I guess my question boils down to this: Is there some sort of inheritance or composition
>> mechanism that allows me to combine any definition for the "room" term I might have in the
>> http://example.org/ context with the definition of "hydra:member"?
>> 
>> Or am I barking up the wrong tree here, and there are other, better options to achieve all or
>> some of the goals stated above?

There's rdfs:subPropertyOf but I don't know if you want (should) go down that route.


> Or at least I am not sure about your motivation to alias your rooms
> with :member :-) 

Shedding some light on your motivation to do so would indeed be helpful.


Cheers,
Markus


[1] http://www.w3.org/TR/json-ld/#default-vocabulary


--
Markus Lanthaler
@markuslanthaler

Received on Thursday, 26 November 2015 18:39:30 UTC