RE: Inheritance / composition of term definitions

On 27 Nov 2015 at 20:53, Karol Szczepański wrote:
> On 27 Nov 2015 at 17:27, Thomas Hoppe wrote:
>> On 27 Nov 2015 at 17:04, Lukas Graf wrote:
>>> On 26 Nov 2015, at 19:38, Markus Lanthaler wrote:
>>>> 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.
>>> 
>>> Development is happening at https://github.com/plone/plone.restapi and
>>> preliminary docs are at http://plonerestapi.readthedocs.org
>>> 
>>> (The demo linked in the README unfortunately is currently pretty
>>> outdated, updating that is on my list of todos).
>>> 
>>> The API has been initiated with a docs-first approach, and large
>>> parts of the implementation are currently just stubbed out. Also,
>>> the parts concerning JSON-LD and Hydra are still very much in
>>> flux.

Thanks for the pointers. I'm really excited about this project. Please keep us posted on your progress and let us know when it is ready to be featured on hydra-cg.com


>>>>>> 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.
>>> 
>>> The thing is, the CMS allows developers (and even end-users) to create
>>> custom content types with their own schemata, validators etc.. Even
>>> through the web, in a declarative fashion without much programming. This
>>> is one of the primary use cases for this CMS, lots of people don't even
>>> bother with the stock content types but primarily implement their own
>>> (Plone happens to sit in a weird place between a CMS application and a
>>> CMS *framework* actually).
>>> 
>>> So there's no way we could know in advance what content types and
>>> schemata our users will come up.

Right. You would define a namespace for those user-defined concepts such as
http://example.com/whatever# and then use that as the value of @vocab. All the terms that aren't mapped to something else, will be automatically be assumed to come from that namespace then.


>>> My idea to address this is to
>>> allow content type developers to annotate their schemata with some
>>> sort of semantic hints (tagged values maybe), for example if
>>> they'd like to indicate that they content type is a
>>> schema.org/Person. With these hints and the basic information
>>> provided by the content types schema, we would then dynamically
>>> generate contexts for each content type. Without additional hints
>>> these would basically boil down to an enumeration of the available
>>> fields, whether they're required for that CT or not, and the
>>> field's types.

I did the same in my Symfony Hydra bundle. It's definitely a sound approach. Just wanted to let you know about @vocab in case you weren't aware of it.


>>> But @vocab seems like a very useful tool to manage namespacing and
>>> avoid littering our attributes with prefixes.

... while at the same time keeping the context small.


>>>>>> 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?
>>> 
>>> Because I thought we had to ;-)

I see :-)


>>> The goal is to use Hydra to provide discoverability for our API.
>>> Eventually, we would like to enable people to build smart clients
>>> that can figure out on their own that X is a folderish type where
>>> resources of type Y can be added to, and use the information from
>>> type Y's context to provide the user with a form to enter the
>>> required fields. So similar to what your Hydra Console does for
>>> the /users or /issues endpoints of the api-demo.

There are basically three options:
  - use generic concepts such as Hydra's collection
  - use domain specific concepts
  - use both at the same time (might be tricky in some cases or result in duplication)


>>> I don't quite understand yet what exactly the requirements are for
>>> a service to be able to fullfill that. Does the containing
>>> resource necessarily have to be of type hydra:Collection (or a
>>> subclass thereof)? Or are those capabilities mainly enabled by the
>>> hydra:Operation's defined for /users?

I would look at this as follows. A Hydra-aware client will only understand the Hydra Core Vocabulary, no application-specific vocabulary. As such, you can expect functionality enabled by the Hydra vocabulary (paginate through collections, filter collections, execute operations etc., fill IRI templates, ...).

What functionality would you want from a generic Hydra client for your API?

 
>>>>>> - 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?
>>> 
>>> Ah, I think Dietrich is onto something here - this might be the main
>>> point where I got confused.
>>> 
>>> We definitely do need to be able to access contentish resources (a single
>>> room in this case) via their own URL.

Dietrich was referring to the currently implicit "containerish resource" though. Should the set of rooms be accessible directly or just by going through a building resource?


>>> But: I now realize that the example I've constructed here is
>>> flawed in the sense that it misrepresents how our CMS works - if a
>>> content type is folderish, its children are accessed via an
>>> attribute that's called the same for all folderish types, so there
>>> would be no "rooms" attribute on our data model. The case were
>>> we're dealing with named collections only applies to lists of
>>> references, not containment. Sorry about that, I somehow managed
>>> to mix those two together :-/
>>>
>>> So the statement I made above "Keep the name "rooms" (instead of "member")" doesn't
>>> actually apply.

In other words, hydra:member would be fine then, right?


>>> However, there might still be a need for us to have the collection sit in beetween the
>>> container and the contained object, because our containers also have their own metadata
>>> needs to be accessible. So if we were to simply map containment to HTTP like
>>> 
>>> GET /buildings/main/ - retrieves the collection members of the "main" building
>>> GET /buildings/main/lobby - retrieves the "lobby" room
>>> (POST /buildings/main/ - create a new "Room" resource in the "main" building)
>>> 
>>> we wouldn't have a way to access the collection's metadata (the building's "address" for
>>> example). So for that reason it seems we do need some intermediate level between the
>>> container and the contentish resource.

Why not? GET /buildings/main/ could return that metadata, no? But yeah, it would be totally fine to have something like

GET /buildings/main/ - retrieves information about the "main" building
GET /buildings/main/rooms - retrieves the collection members of the "main" building
GET /buildings/main/rooms/lobby - retrieves the "lobby" room
POST /buildings/main/rooms - create a new "Room" resource in the "main" building


>> No one prevents you from using the "other dimensions" of an IRI such as the
>> query string to differentiate here.
>> For example to interact with the meta data part of a resource, you can just
>> have a ?meta in the URL.
>> That's still restful as a different IRI can point to a completely different
>> resource, even if the difference is only in the query string.

Yeah, how the URL looks like doesn't matter... in fact it shouldn't matter.


> I'd disagree - it needs a client to know something extra.

Apart from the URL, what would it need to know that it wouldn't need to know otherwise?
 

> I'd go with something that's a common ground for both client and server -
> HTTP feature.
> Meaybe a verb (i.e. OPTIONS - only drawback is that responses are not
> cacheable), a specific acceptable content type or a request Link header with
> some specific rel, i.e. meta.

That's much, much more complicated to communicate to the client than just pointing to a separate resource.


> I think an extra query string parameter is far from what ReST presents.
> Optionally, you could indeed have that query string parameter, but this
> should be additionally described with some hypermedia controls achieveing
> both ReST and HATOAS simultanously.

Of course.


> In general, we've touched a matter of having data and meta-data/hypermedia
> controls mixed in several discussions now. I personally prefer to push that
> out of the data i.e. to headers or separate request or separate RDF graph. I
> believe Hydra spec is silent in this area.

I'm not a big fan of separating it.


>>>>>> - 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?
>>> 
>>> That's definitely a use case as well, but we'll handle that via a
>>> separate search / query endpoint. My idea was that any client that
>>> is Hydra capable (?) could then identify /buildings as a
>>> collection, and have (or know where to find) the necessary
>>> information on how to add a resource to that collection, without
>>> any other knowledge about the underlying domain-specific models.

Adding items to a collection requires an operation. But using hydra:member would tell a client where to find the items of the collection.


>>> Also, batching / pagination will definitely be something we'll
>>> need to implement. So hydra's PartialCollectionView would possibly
>>> come into play for that.
>>> 
>>>> 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.
>>> 
>>> After Dietrich and your explanations, I don't think that's what we want (or need).

Good, that simplifies things.


[...]

>>>>> 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.
>>> 
>>> I can't necessarily speak for other contributors to our API here,
>>> but what I'd like to accomplish with Hydra is to point your Hydra
>>> console (or a Hydra client reference implementation, if there is /
>>> will be be such a thing) at our API, and basically have it provide
>>> the same capabilities that it provides for your api-demo endpoint.

That's a fantastic goal to strive for. We are working hard to make the capabilities offered by such generic tools as compelling as possible.


>>> hydra:member is what we see being used in the example section "5.1
>>> Collections" of the Hydra spec ;-) But honestly, it's not quite
>>> clear to me what exactly we would gain with using
>>> hydra:Collection, resp. what we'd lose if we wouldn't be using it.

At the moment, not too much. But we are already changing that with filtering...


>>> In the case of PartialCollectionView it's much more concrete:

... and pagination is obviously another use case. You need to use it with hydra:Collection and hydra:member to enable a client to actually browse through the pages and reconstruct the complete collection.


>>> Providing a standardized way to represent pagination URLs would
>>> satisfy the hypermedia-driven aspect for our API for that case,
>>> where a client wouldn't have to build their own URLs.
>>> 
>>> I hope I was able to provide *some* more background on our
>>> motivation and use cases.
>>> 
>>> And while I'm trying to keep this Hydra related and want to avoid
>>> this thread becoming a support case for our own cause, I really do
>>> appreciate you guys taking the time to find out what it is we
>>> need.

Don't worry about that. Quite the contrary. It helps immensely to understand how people (intend to) use Hydra. It ensure we are building the right thing and shows us what aspects aren't as fleshed out as they should be. So please keep the questions coming regardless of how specific they are to your use cases.


--
Markus Lanthaler
@markuslanthaler

Received on Saturday, 28 November 2015 16:01:40 UTC