Re: Inheritance / composition of term definitions

On 28 Nov 2015, at 16:56, Markus Lanthaler <markus.lanthaler@gmx.net> wrote:

> 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:
>>>>>>> [...]

>>>> The goal is to use Hydra to provide discoverability for our API.
>>>> 
>>>> 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 think based on the information from this thread I'm currently leaning towards using the generic Hydra collection type for now, but aliased to a different term name (like "children" or "items"). If you've never heard of Hydra or RDF and just look at the JSON data structure, the singular "member" does look rather strange.

I thought about whether there could be a need to annotate that relationship with some domain specific information, but I really don't see any. For the primary use of representing our folderish types the relationship is always the same: containment, the collection members are children of a parent container. We have other cases of collection, like attributes that contain lists of references to other objects, or collections based on persisted search queries (like reports), but IMHO those are different enought to be treated separately.

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

That's a good question. A general purpose, generic Hydra client would obviously be limited to some basic concepts related to dealing with resources.

One thing that I could imagine would be a general purpose, read-only "resource explorer". Sort of a browser that is capable of building a navigation tree for the content behind the API, allows navigation through the content structure, and possibly can do structured queries / full text search.

I different use case I see is that of a self-documenting API. A generic Hydra client could be used to extract documentation from the API itself, and either compile it to a document that a developer can use to work with that API, or use it to build forms that can be used to prompt a user for the information necessary to submit valid requests to the API (like Hydra console).   

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

Ah, I see, I misunderstood that. I don't think we need or want that.

Our CMS works by exposing database objects in a rather direct way through traversal. The underlying database (ZODB) is inherently hierarchical. Everything starts from a root object, and database objects can be added as children of other objects. Each object gets an ID that is unique in the context of the container (distinguishes it from its siblings). Those IDs then make up the path of the object, which, given adequate permissions, workflow state, etc., is published as an HTTP resource. So already for the regular HTTP interface used by web browsers, the URLs for our objects look like /buildings/main-building/lobby. The approach for the REST API is to use exactly the same URL, but instead return a JSON representation of the object instead of HTML.

So with a web browser, for /buildings/main-building you (usually) get both - the "metadata" (or attributes) of the folderish building types, as well as the immediate children.

If we were to build the API in a way that allows to directly access the collection (as in, returns a JSON array), we would need to have some other way of accessing the folderish object's properties. 


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

Correct, we would probably just alias it to something like "children" or "items".

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

In the example just above I was thinking of a response that directly contains the collection members as a JSON array on the top level.

> 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

Yeah, that's what I was contemplating. Because the folderish type doesn't provide a natural name like "rooms" for its children, it would probably something generic like /buildings/main/items/lobby. The issue with that is that it doesn't map very naturally to the way traversal and object publishing work in our CMS - we'd somehow have to "consume" that "items" part before letting traversal continue. But, while that would certainly be doable, I think for users to be able to use exactly the same paths they see in their browser address bar to access a different representation of that object via the API has some great value.

So I think we actually should stick with a term that maps to hydra:member (whatever we end up calling it).

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

In our case, we can't even separate them in a meaningful way. DC metadata like creation date or last modification are pretty much first class citizens, like any other properties. They might be hidden from some forms and set by the system, but otherwise they don't really behave any differently. 

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

That's good to know. I think that'll be what we're shooting for.


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

Since a general purpose API for our CMS has been our roadmap for a while now, I did looke at some other standards in the past, specifically CMIS and OData. While I rather quickly dismissed OData for being tied much too closely to any internal data models (and doing weird things to HTTP), CMIS did look very interesting. For CMIS there's already a couple general purpose clients / repository explorers around, among them Apache Chemistry CMIS Workbench [1], which is pretty rich in features. That might be of interest to you if you haven't seen it.


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

That settles it then ;-) We definitely do need pagination of some description, so I think hydra:Collection is a good fit here.

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

Great, will do!

Thanks,

Lukas


[1] http://chemistry.apache.org/java/developing/tools/dev-tools-workbench.html

Received on Tuesday, 1 December 2015 00:15:56 UTC