Re: Inheritance / composition of term definitions

Hi Lukas, 

sorry for the late reply. Comments inline. 
Am 22.11.2015 21:22 schrieb Lukas Graf <lukas.graf.bern@gmail.com>:
>
> Dear all, 
>
> 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. 
>
> 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. 
>
> 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. 
>
> 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. 
>
> 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. 
>
> 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". 
>
> 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.

> - Have the term be part of the domain specific JSON-LD context 

"rooms" with an array value resolves to many single assertions about the building in the underlying data model:

/buildings/main :rooms /lobby
/buildings/main :rooms /blueroom

Each statement names one thing which is a room of the main building. 

> - 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 

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.

> - 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" 
>     } 
>   ], 
>   // ... 
> } 
>

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. 

>
> 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? 

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

HTH
Dietrich 

Am 22.11.2015 21:22 schrieb Lukas Graf <lukas.graf.bern@gmail.com>:

Dear all,

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.

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.

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.

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.

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.

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".

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
- 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
- Not having to move the "name" and "address" properties into their own sub-object

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"
    }
  ],
  // ...
}

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?

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?

Thanks,

Lukas

Received on Wednesday, 25 November 2015 17:40:49 UTC