HydraCG / Specifications

Specifications created by the Hydra W3C Community Group
Other
138 stars 26 forks source link

EntryPoint question #155

Open paul opened 6 years ago

paul commented 6 years ago

I'm having trouble figuring out the "correct" way to have an EntryPoint. The use-cases documentation for Entry Point 1.entry-point.md has an example where all the links are inside a "collection" attribute. The Hydra Console demo app has instead the links as attributes at the root level. I assume that the use-case example is just newer, and top-level attributes is no longer the correct way to do it?

I think however, the newer "style" is not as useful because there's no human-friendly "name" by which to find the link. For example, if I'm scripting a client to go get all the Issues from the entry point, in the old style I just look for "issues" attribute. In the new style, though, if I want to do the same for Events, I'm not even sure what to look for. @id is [http://example.com]/api/events, and "title" is a totally human "List of Events". There's the manages.object attribute with "schema:Event", but I think this just says that this collection is a collection of Events. Ideally, I'd be able to tell my client "go look in the entry point document for "events" (or "allEvents" or something) and follow that URL". There doesn't seem to be any way to do that in the current scheme.

Sort of tangentially related, I also notice that the supportedOperations for all the entry point items are always "POST". Is a "GET" operation on all URLs just always assumed to be possible? If so, how do I specify a resource to only support POST, and disallow GET?

lanthaler commented 6 years ago

Both are totally valid. The advantage of the approach used in the use case document is that you won’t have to invent your own properties such as “events”, “issues” etc. that no one else will understand. Instead you can leverage the existing types. You would retrieve the entry point and then look for a collection that manages objects of the desired type, e.g., schema:Event.

Collections are subclasses of hydra:Resource which means they are de-referenceable. In other words, yes, you should assume that such entities can be retrieved with a GET.

lanthaler commented 6 years ago

@alien-mcl, might be worth adding a test showing how this works and include that also in the use case document. WDYT?

alien-mcl commented 6 years ago

Sure thing - I'll try to set it up.

Still, I'm somehow confused with what @paul wrote in his issues example. I think it's more related to how the JSON-LD payload is returned by the server. If it doesn't fit client's purpose it can always frame it so it has what the client needs.

alien-mcl commented 6 years ago

BTW. I've reviewd history of that 1.entry-point.md and it seems that at the very beginning indeed entryPoint had one relation named collection (somehow unfortunate in this case - it could be named events) pointing to events.

After some changes this relation was extended with two more pointed resources. I feel that generic collection name caused this disturbance. This property/relation name doesn't have any specific meaning and indeed it could be replaced with three relations named accordingly to what pointed resources are providing.

paul commented 6 years ago

Oh, I see! So am I correct that the "collection" attribute at the top-level wasn't meant to imply that it is a "collection" of entry-point links, but rather that the object contained within is itself a Collection?

@alien-mcl I was also digging through the history of 1.entry-point.md to figure out the intent, and it looks like whomever added the additional links was confused in the same way.

As for my "issues" example, let me be more specific. Lets say I'm writing a command-line tool that will import all Issues from the system described by the API and do something with them (save them to a local database, tweet about them, or publish them to another API). In a dumb CRUD API, I would write a client like get("http://example.com/issues").each { do_something_with_issue }. In an enlightened Hypermedia API, however, I know that "/issues" can change at any point, so I'm better off starting at the entry point and following a link to get to the resource for "all issues". With the "Issue Tracker example API", I can have my script look for the attribute "http://www.markus-lanthaler.com/hydra/api-demo/vocab#EntryPoint/issues" in the expanded JSONLD document. I could have my script do something like api("http://example.com/").dereference("EntryPoint/issues").each { ... }

In the EntryPoint given in the 1.entry-point.md, I'm not sure how to do that. I was mistakenly trying to "select" the Issues item from the "collection" attribute, because of the misunderstanding I had. (As an aside, it would be extremely helpful if the Context for that EntryPoint was provided in that example.) How would I use that EntryPoint to "discover" the URL for the "events" (or in the example given, "events") resource?

lanthaler commented 6 years ago

We introduced the collection property to link to related collections without requiring users to invent dedicated properties for each of them. The way I would see a client to work with this is something along the lines of:

client
  .retrieve("http://example.com/")
  .resources()
  .ofType("hydra:Collection")
  .where(resource => resource[hydra.manages][hydra.property] == rdf.type 
      && resource[hydra.manages][hydra.object] == schema.Event);
  .first()
  .members()
  .each( ... );

or, if you would like to make client a bit more aware of Hydra

client
  .retrieve("http://example.com/")
  .collections()
  .thatManageMembersOfType(schema.Event)
  .first()
  .members()
  .each( ... );
paul commented 6 years ago

I see. So its expected that there will only ever be one resource in that collection that manages schema.Events? I suppose that's the case, since things like "events created by me" and "events I've subscribed to" would be exposed as filters on that collection of events...

What does it look like if the EntryPoint links to something that's not a collection? "Invent a property", like you said?

alien-mcl commented 6 years ago

As for the test mentioned, I think there is already such one. In the integration tests suite, file served as an entry point contains two collections exposed with examplevocab:events and examplevocab:people. The test obtains first one using client's API. Indeed we could introduce a helper i.e. collections within the IHypermediaContainer type exposed as hypermedia property that would enable easier access to collections.

paul commented 6 years ago

@alien-mcl I'm sorry, I'm not sure I'm following. That Heracles test EntryPoint has two links, both as top-level items. The EntryPoint in the use-case document has a "collection" top-level attribute as an array of collection items. The Heracles EntryPoint as the advantage of having a simple "key" that can be used to find the item ("examplevocab:Events"). I guess that since JSON+LD, both those EntryPoint document structures are (or can be made to be) equivalent, but I'd really love to see the context document for the use-case EntryPoint.

I'm also not sure how to link to a resource that is not a collection in the use-case EntryPoint style, I think the docs could use an example of that.

lanthaler commented 6 years ago

I see. So its expected that there will only ever be one resource in that collection that manages schema.Events? I suppose that's the case, since things like "events created by me" and "events I've subscribed to" would be exposed as filters on that collection of events...

A collection with multiple manage blocks would be able to describe that:

  "collection": [
    {
      "@id": "/events/createdByMe",
      "@type": "Collection",
      "manages": [{
        "property": "rdf:type",
        "object": "schema:Event"
      }, {
        "property": "createdBy",
        "object": "/people/markus"
      }]
    }, {
      "@id": "/events/IsubscribedTo",
      "@type": "Collection",
      "manages": [{
        "property": "rdf:type",
        "object": "schema:Event"
      }, {
        "subject": "/people/markus"
        "property": "follows",
      }]
    }

What does it look like if the EntryPoint links to something that's not a collection? "Invent a property", like you said?

At the moment, yes. We actually didn't discuss this much so far.

alien-mcl commented 6 years ago

I guess that since JSON+LD, both those EntryPoint document structures are (or can be made to be) >>equivalent

Indeed - doesn't really matter what is the name of the relation. Current reference client hooks up the @type of the resource.

I'd really love to see the context document for the use-case EntryPoint.

Here it is. Probably it may be incorrect by means the use case uses collection property and the context does not define a @vocab.

What does it look like if the EntryPoint links to something that's not a collection?

There is a new unit test here that uses some (nested) resources with a custom link. Current implementation assumes that the relation must be marked with hydra:Link in order to be discovered and exposed in the links property of the client's API. Whether this requirements will preserve - time will show :)

lanthaler commented 6 years ago

Indeed - doesn't really matter what is the name of the relation. Current reference client hooks up the @type of the resource.

It does (unless there are other means such as manages), as otherwise a client isn't able to choose among a set of collections.

alien-mcl commented 6 years ago

Yes - manages gives a hint to the client on the collection's semantics, but still, it is irrelevant from data model point of view. For client - the resource should be either typed as hydra:Collection or the relation between the owner of the collection and the collection should inference that type (i.e. hydra:collection of which I wasn't fully aware).