Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Actions with explicit target #154

Open
wants to merge 7 commits into
base: master
Choose a base branch
from

Conversation

elf-pavlik
Copy link
Member

@elf-pavlik elf-pavlik commented Jan 6, 2018

obviously NOT READY TO MERGE

This PR serves as starting point for considering actions/operations with explicit target, I reuse terms from schema: namespace - schema:potentialAction & schema:target just because they seem to have same purpose and we already use other terms from that namespace.

I would also suggest not to focus on the client pseudo code and update it with Heracles.ts based code as the reference implementation of the client progresses.

As discussed in on of the previous issues, it seems that we have something like:

hydra:operation rdfs:subPropertyOf schema:potentialAction .
hydra:Operation rdfs:subClassOf schema:Action .

so more specific hydra:operation implies the target of referenced hydra:Operation, while schema:potentialAction leaves it to schema:Action to make the target explicit via schema:target.


This change is Reviewable

@lanthaler lanthaler changed the title actions with explicit target Actions with explicit target Jan 7, 2018
@lanthaler
Copy link
Member

I think of operations as descriptions of (HTTP) requests and actions as the abstract, semantic meaning they have. I think we discussed that before. I think mixing the two (as in sub-classing which means a single resource is both an action and an operation at the same time) will be confusing and lead to all sort of unintended side effects.


Reviewed 2 of 2 files at r1.
Review status: all files reviewed at latest revision, 6 unresolved discussions.


drafts/use-cases/5.1.creating-event-with-put.md, line 33 at r1 (raw file):

if (operation) {
  var templateVariables = {
      'schema:name' : 'meeting with-will'

At some point we should discuss how to get rid of this. The client shouldn't need to care where such information goes. It should just be concerned with providing all the necessary data.

In this case here, providing the event would be enough. In some cases, however, the relationship between the payload and IRI parameters isn't as straightforward though


drafts/use-cases/5.1.creating-event-with-put.md, line 67 at r1 (raw file):

    "totalItems": 0,
    "members": [ ],
    "schema:potentialAction": {

Hmm... we loose important information here. Would you see the two mechanisms to co-exist or, as this change suggests, that schema:potentialAction replaces memberTemplate?


drafts/use-cases/7.searching-events.md, line 19 at r1 (raw file):

getOperationOfType

Do you suggest that clients treat values of schema:potentialAction as Operation?


drafts/use-cases/7.searching-events.md, line 22 at r1 (raw file):

some tex


drafts/use-cases/7.searching-events.md, line 25 at r1 (raw file):

invoke

You seem to assume that GET is the default HTTP operation if unspecified. I'm not convinced we should do that for operations. Could you please make the method explicit below.


drafts/use-cases/7.searching-events.md, line 102 at r1 (raw file):

Some event having a search phrase: some text

Let's make a better example by describing a real event. We could, e.g., describe a Hydra conference call here.


Comments from Reviewable

@elf-pavlik
Copy link
Member Author

Review status: all files reviewed at latest revision, 6 unresolved discussions.


drafts/use-cases/5.1.creating-event-with-put.md, line 33 at r1 (raw file):

Previously, lanthaler (Markus Lanthaler) wrote…

At some point we should discuss how to get rid of this. The client shouldn't need to care where such information goes. It should just be concerned with providing all the necessary data.

In this case here, providing the event would be enough. In some cases, however, the relationship between the payload and IRI parameters isn't as straightforward though

Makes sense. As I mentioned in comment of this PR, we might even consider to remove that pseudo-code here and gradually re-add it following Herakles.ts features development.


drafts/use-cases/5.1.creating-event-with-put.md, line 67 at r1 (raw file):

Previously, lanthaler (Markus Lanthaler) wrote…

Hmm... we loose important information here. Would you see the two mechanisms to co-exist or, as this change suggests, that schema:potentialAction replaces memberTemplate?

Do you mean that we would use named node with @id for IriTemplate and reference it in two different places? I'll take a look at issues to understand other use cases for memberTemplate than adding new members.


drafts/use-cases/7.searching-events.md, line 19 at r1 (raw file):

Previously, lanthaler (Markus Lanthaler) wrote…

getOperationOfType

Do you suggest that clients treat values of schema:potentialAction as Operation?

I think client could provide single interface for action with explicit target and operations with target implied by operation property. We could discuss it in more depth while implementing in Herakles, possibly it would just handle making internally implicit targets explicit and then handle them in the same way.


drafts/use-cases/7.searching-events.md, line 25 at r1 (raw file):

Previously, lanthaler (Markus Lanthaler) wrote…

invoke

You seem to assume that GET is the default HTTP operation if unspecified. I'm not convinced we should do that for operations. Could you please make the method explicit below.

good catch! I'll add "method": "GET" to the schema:SearchAction


drafts/use-cases/7.searching-events.md, line 102 at r1 (raw file):

Previously, lanthaler (Markus Lanthaler) wrote…

Some event having a search phrase: some text

Let's make a better example by describing a real event. We could, e.g., describe a Hydra conference call here.

👍


Comments from Reviewable

@elf-pavlik
Copy link
Member Author

Review status: 1 of 2 files reviewed at latest revision, 6 unresolved discussions.


drafts/use-cases/7.searching-events.md, line 22 at r1 (raw file):

Previously, lanthaler (Markus Lanthaler) wrote…

some tex

Done.


drafts/use-cases/7.searching-events.md, line 25 at r1 (raw file):

Previously, elf-pavlik (elf Pavlik) wrote…

good catch! I'll add "method": "GET" to the schema:SearchAction

Done.


drafts/use-cases/7.searching-events.md, line 102 at r1 (raw file):

Previously, elf-pavlik (elf Pavlik) wrote…

👍

Done.


Comments from Reviewable

@lanthaler
Copy link
Member

Here's a rough sketch of what I mentioned on the call earlier today:

{
  "@context": "/api/context.jsonld",
  "@id": "/api/events",
  "@type": "Collection",
  ...
  "**action**": {
    "@type": "schema:AddAction",
    "title": "Add an event to this collection",
    "**request**": {
      "@type": "Operation",
      "method": "PUT",
      "expects": "schema:Event",
      "target": {
        "@type": "IriTemplate",
        ...
      }
    }
  }
}

I introduced **action** and **request**. I'm quite unhappy with the name of the latter but couldn't come up with something better yet (handler might work but I didn't like it too much either). You also see target being used in the operation, that's not new though, it is just the reverse of hydra:operation.

What do you think about the general structure of such an approach (ignoring the naming of those new terms for the time being)?


Review status: 1 of 2 files reviewed at latest revision, 3 unresolved discussions.


drafts/use-cases/5.1.creating-event-with-put.md, line 67 at r1 (raw file):

Previously, elf-pavlik (elf Pavlik) wrote…

Do you mean that we would use named node with @id for IriTemplate and reference it in two different places? I'll take a look at issues to understand other use cases for memberTemplate than adding new members.

No, I meant that you removed memberTemplate which describes the URL space to clients and allows, e.g., direct lookups, without introducing an alternative to enable the same.


Comments from Reviewable

@alien-mcl
Copy link
Member

How would a similar example look like for target not being an IriTemplate? Simple { "@id": "http://..." }, a string?

I was also thinking from an API point of view. Currently, an operation is associated with owning resource (a resource that is a subject of the relation with operation) and the target URL of the operation is taken from that owning resource. It is somehow invoking an operation on that owning resource.

Here we have an owning resource that has an action that points somewhere else. This somewhere else sometimes will be that owning resource, but it may be completely different. In an API, we would then invoke an action on an owning resource but actually it may be untrue (as a the target may be completely different one). This may lead to misunderstandings.


Review status: 1 of 2 files reviewed at latest revision, 3 unresolved discussions.


drafts/use-cases/5.1.creating-event-with-put.md, line 33 at r1 (raw file):

Previously, elf-pavlik (elf Pavlik) wrote…

Makes sense. As I mentioned in comment of this PR, we might even consider to remove that pseudo-code here and gradually re-add it following Herakles.ts features development.

Yep, let's leave it for now as it seems unrelated to the clue of this PR.


drafts/use-cases/7.searching-events.md, line 19 at r1 (raw file):

Previously, elf-pavlik (elf Pavlik) wrote…

I think client could provide single interface for action with explicit target and operations with target implied by operation property. We could discuss it in more depth while implementing in Herakles, possibly it would just handle making internally implicit targets explicit and then handle them in the same way.

I'd introduce separate method, i.e. getActionOfType - my understanding is action is somehow an accusative (if I can say it that way) for the operation as it changes position of the target within a sentence (if you know what I mean).


Comments from Reviewable

@lanthaler
Copy link
Member

How would a similar example look like for target not being an IriTemplate? Simple { "@id": "http://..." }, a string?

Almost exactly the same:

{
  "@context": "/api/context.jsonld",
  "@id": "/api/events",
  "@type": "Collection",
  ...
  "**action**": {
    "@type": "schema:AddAction",
    "title": "Add an event to this collection",
    "**request**": {
      "@type": "Operation",
      "method": "PUT",
      "expects": "schema:Event",
      "target": {
        "@id": "http://...",
        ...
      }
    }
  }
}

The important part here is that the value of targetMUST NOT be of type IriTemplate in this case.

Here we have an owning resource that has an action that points somewhere else. This somewhere else sometimes will be that owning resource, but it may be completely different. In an API, we would then invoke an action on an owning resource but actually it may be untrue (as a the target may be completely different one). This may lead to misunderstandings.

Sure. That's how pretty much every HTML form out there works too. Why do you think this would lead to misunderstandings?


Reviewed 1 of 1 files at r2.
Review status: all files reviewed at latest revision, 3 unresolved discussions.


Comments from Reviewable

@alien-mcl
Copy link
Member

That's how pretty much every HTML form out there works too

Well, yes and no - page has an intermediate object that actually does that - the form. From the API point of view you don't submit the page, but the form - you invoke an action on the form and there is no confusion here.

In our case an operation is owned by the resource and points to it. In case of the action - the action may not point to the owning resource.

client.invoke(events.operations.first());
// vs
client.invoke(events.actions.first()); // <- collection owns the action, but the action may point to the collection

Both looks very similar, but may have drastically different behaviors.


Review status: all files reviewed at latest revision, 3 unresolved discussions.


Comments from Reviewable

@lanthaler
Copy link
Member

Well, yes and no - page has an intermediate object that actually does that - the form.

What the difference between a HTML form and a Hydra Operation in your opinion?

From the API point of view you don't submit the page, but the form

s/page/resource/
s/form/operation/


Review status: all files reviewed at latest revision, 3 unresolved discussions.


Comments from Reviewable

@asbjornu
Copy link
Member

I introduced **action** and **request**. I'm quite unhappy with the name of the latter but couldn't come up with something better yet (handler might work but I didn't like it too much either).

If I understand the object within request correctly, I agree that request isn't the best name. What about form or recipe?


Review status: all files reviewed at latest revision, 3 unresolved discussions.


Comments from Reviewable

@elf-pavlik
Copy link
Member Author

I like your snippets @lanthaler, I could update this PR to reflect it! If we would merge it at some point, the we would have to update all the other snippets to separate actions from handlers (operations).

I introduced action and request. I'm quite unhappy with the name of the latter but couldn't come up with something better yet (handler might work but I didn't like it too much either).

I recall an old Activity Streams 2.0 related draft which never even made it to Workin Draft stage, I have a copy of it on http://elf-pavlik.github.io/w3c-socialwg-activitystreams/activitystreams2-actions.html it uses concept of actions and handlers. Since property names should describe meaning of the relation we could even consider names like handledWith (instead of request) and affords (instead of action). Also if we separate actions from handlers (operations). Resources would most likely reference actions directly via action / affords and possibly not reference handlers directly via operation / "@reverse": "target".
As one of major gains in this change I see the uniform discovery of all the actions via affords / action, no matter which resource handlers of those actions specify as their target. So operation (property) would rarely get used its original direction and pretty much always the reverse direction - target would get used to relate action to its handler (operation).


Review status: all files reviewed at latest revision, 3 unresolved discussions.


drafts/use-cases/5.1.creating-event-with-put.md, line 67 at r1 (raw file):

Previously, lanthaler (Markus Lanthaler) wrote…

No, I meant that you removed memberTemplate which describes the URL space to clients and allows, e.g., direct lookups, without introducing an alternative to enable the same.

I don't think any of current use cases exemplifies requirement for such 'direct lookups'. Maybe until someone proposes (via PR) a clear use case for such 'direct lookups', we will not try to deal with that requirement?


Comments from Reviewable

@lanthaler
Copy link
Member

Since property names should describe meaning of the relation we could even consider names like handledWith (instead of request)

I quite like handledWith. I'm not a native speaker but handledBy sounds slightly better to me. Perhaps executedBy / executableBy or something similar would be even more intuitive.

and affords (instead of action).

I know that the term affordance is en vogue in API circles but I have yet to find a person outside this small community to understand it :-)

Also if we separate actions from handlers (operations). Resources would most likely reference actions directly via action / affords and possibly not reference handlers directly via operation

That would require developers to spell out the same URL twice, right? I guess having a few examples (perhaps in a separate markdown file for now) would help to move this discussion forward. Could you please amend the PR with what you had in mind? Thanks


Review status: all files reviewed at latest revision, 3 unresolved discussions.


Comments from Reviewable

@alien-mcl
Copy link
Member

I think terms ending with by may point to a person while those ending with with fit better to tools.


Review status: all files reviewed at latest revision, 3 unresolved discussions.


Comments from Reviewable

@elf-pavlik
Copy link
Member Author

If we take https://github.com/HydraCG/Specifications/blob/master/drafts/use-cases/6.updating-event.md#details it would look something like:

{
    "@context": "/api/context.jsonld",
    "@id": "/api/events/1",
    "@type": ["schema:Event"],
    "action": [
        {
           "@type":  "schema:ReplaceAction",
           "title": "Update an existing event",
           "handledWith": {
              "@type": "Operation",
              "method": "PUT",
              "expects": "schema:Event",
              "target":  "/api/events/1"
          }
       }
    ]
}

One could frame it differently not to repeat /api/events/1 but then we may need to use a reference for at least one of the blank nodes instead.


Review status: all files reviewed at latest revision, 2 unresolved discussions.


Comments from Reviewable

@elf-pavlik
Copy link
Member Author

I've separated action and operation in almost all snippets. I'll add commit for search via POST and use case 9 soon.


Review status: 0 of 8 files reviewed at latest revision, 2 unresolved discussions.


Comments from Reviewable

@alien-mcl
Copy link
Member

Review status: 0 of 8 files reviewed at latest revision, 3 unresolved discussions.


drafts/use-cases/1.1.security-considerations.md, line 35 at r3 (raw file):

              "method": "POST",
              "expects": "schema:Event",
              "target": "/api/events"

I though it is the action that would have a target defined - operation would still be dependent on it's owner in that manner. This way we would leave operations compatible with current spec. Otherwise I don't see any benefit in introducing actions at all - we could incorporate all those details in operations as we do no i.e. in Heracles.ts (with adding target as this is the only part that's missing)


Comments from Reviewable

@lanthaler
Copy link
Member

@elf-pavlik any update on this?

@tpluscode
Copy link
Contributor

Review status: 0 of 8 files reviewed at latest revision, 6 unresolved discussions.


drafts/use-cases/1.entry-point.md, line 94 at r3 (raw file):

          "method": "POST",
          "expects": "schema:Place",
          "target": "/api/venues"

Isn't it weird to have this id repeated here where it's the subject of action?


drafts/use-cases/5.1.creating-event-with-put.md, line 67 at r1 (raw file):

Previously, elf-pavlik (elf Pavlik) wrote…

I don't think any of current use cases exemplifies requirement for such 'direct lookups'. Maybe until someone proposes (via PR) a clear use case for such 'direct lookups', we will not try to deal with that requirement?

Meaning we actually want to remove memberTemplate completely?


drafts/use-cases/5.1.creating-event-with-put.md, line 28 at r3 (raw file):

var client = new HydraClient();
var operation = client.get('http://example.com/events');
    .getOperationsOfType('http://schema.org/AddAction')

So this should be called getActionsOfType and the operation takes from action.operation?


drafts/use-cases/5.1.creating-event-with-put.md, line 33 at r3 (raw file):

if (operation) {
  var templateVariables = {
      'schema:name' : 'meeting with-will'

So the expansion uses the variable name or the property?
Any why did is change from array to a string?


drafts/use-cases/7.searching-events.md, line 19 at r1 (raw file):

Previously, alien-mcl (Karol Szczepański) wrote…

I'd introduce separate method, i.e. getActionOfType - my understanding is action is somehow an accusative (if I can say it that way) for the operation as it changes position of the target within a sentence (if you know what I mean).

Ah yes, what I commented above. Would see it more like

var operation = client.get(string).getActionOfType(string).operation

Comments from Reviewable

@lanthaler
Copy link
Member

Reviewed 8 of 8 files at r3.
Review status: all files reviewed at latest revision, 6 unresolved discussions.


drafts/use-cases/1.1.security-considerations.md, line 35 at r3 (raw file):

Previously, alien-mcl (Karol Szczepański) wrote…

I though it is the action that would have a target defined - operation would still be dependent on it's owner in that manner. This way we would leave operations compatible with current spec. Otherwise I don't see any benefit in introducing actions at all - we could incorporate all those details in operations as we do no i.e. in Heracles.ts (with adding target as this is the only part that's missing)

Adding it to the action wouldn't work as there might be multiple operations allowing you to perform the action. The use case at hand would be using different protocols like either sending an HTTP request or a GRPC request.


drafts/use-cases/1.entry-point.md, line 94 at r3 (raw file):

Previously, tpluscode (Tomasz Pluskiewicz) wrote…

Isn't it weird to have this id repeated here where it's the subject of action?

For embedded actions/operations it is, yeah. But it may be fine as they would only be used rarely. @elf-pavlik could you please add an example illustrating how this would work in a ApiDocumentation? We would likely support two cases there: a) explicit target and b) implicit target that depends, e.g., on a resource's class


drafts/use-cases/5.1.creating-event-with-put.md, line 67 at r1 (raw file):

Previously, tpluscode (Tomasz Pluskiewicz) wrote…

Meaning we actually want to remove memberTemplate completely?

Yes. Pavlik already replaced it's need for PUTs here. We could do the same for GETs by adding the following action

    {
        "@type": "schema:DiscoverAction",
        "title": "Directly access a member of the collection (if it exists)",
        "operation": {
            "@type": "Operation",
            "method": "GET",
            "target": {
                "@type": "IriTemplate",
                "template": "http://example.com/api/event{/slug*}",
                "variableRepresentation": "BasicRepresentation",
                "mapping": [
                    {
                        "@type": "IriTemplateMapping",
                        "variable": "slug",
                        "property": "schema:name",
                        "required": true
                    }
                ]
            }
        }
    }

drafts/use-cases/5.1.creating-event-with-put.md, line 28 at r3 (raw file):

Previously, tpluscode (Tomasz Pluskiewicz) wrote…

So this should be called getActionsOfType and the operation takes from action.operation?

Or simply something like getOperations() or getOperationsForAction() given that we want to find operations and not actions.


drafts/use-cases/5.1.creating-event-with-put.md, line 33 at r3 (raw file):

Previously, tpluscode (Tomasz Pluskiewicz) wrote…

So the expansion uses the variable name or the property?
Any why did is change from array to a string?

I agree with Pavlik that the application using Heracles should provide the property and not know anything about the variable name as it is an implementation detail that may change at any time.


Comments from Reviewable

@alien-mcl
Copy link
Member

Review status: all files reviewed at latest revision, 6 unresolved discussions.


drafts/use-cases/1.1.security-considerations.md, line 35 at r3 (raw file):

Previously, lanthaler (Markus Lanthaler) wrote…

Adding it to the action wouldn't work as there might be multiple operations allowing you to perform the action. The use case at hand would be using different protocols like either sending an HTTP request or a GRPC request.

Hmm. This just makes the benefits from action event less tempting. If it just to add some semantic to an operation, I think I preferred typing an operation - this way you could have single operation marked with multiple semantics (i.e. same operation adds and creates collection items).

BTW. How would you pick the operation matching a desired protocol?


Comments from Reviewable

@elf-pavlik
Copy link
Member Author

My apologies everyone for staying gone offline for so long. We had real mess with changing to faster and more reliable broadband in our pretty remote home. I hope from now on we should enjoy stable connection.

I'd like to point a major problem this PR tries to solve, if we look at pseudo code of current use cases:

Currently client needs to have prior knowledge of which one of those server uses and write different code based on that prior knowledge. IMO client shouldn't have to do that and same code should handle both of those cases. Separating the semantic action which client intends to perform, from operation which provides server specific details of how to perform (handle) that action looks like promising approach.

I would propose to focus first on the part of this pull request related to just those two use cases UC5 & UC5.1

While I wanted to avoid getting stuck in details of the pseudo code, now I think that if we want to have same code handling both cases, it might make sense to take a moment to agree on that pseudo code or even take a small detour to try implement in in Heracles.ts

currently common part of pseud code in UC5 & UC5.1

var event = {
    "@context": "/api/context.jsonld",
    "@type": "schema:Event",
    "eventName": "My brand new event",
    "eventDescription": "Hope it will work",
    "startDate": "2017-04-19",
    "endDate": "2017-04-19"
};
var client = new HydraClient();

UC5 specific

var operation = client.get("http://example.com")
    .getApiDocumentation()
    .getEntryPoint()
    .getCollection({
      property: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
      object: "http://schema.org/Event"
      })
    .getOperationOfType('http://schema.org/CreateAction');
client.invoke(operation, event);

UC5.1 specific

var templateVariables = {
    slug: [
        'meeting',
        'with-will'
    ]
};

var memberTemplate = client.get('http://example.com/events').memberTemplate;
var operation = memberTemplate
    .getOperationsOfType('http://schema.org/CreateAction')
    .thatExpect('http://schema.org/Event')
    .first();

const operationWithTargetExpanded = operation.expandTarget(templateVariables);
client.invoke(operationWithTargetExpanded, event);

Since in UC5.1 mapping for IriTemplate includes

{
                "@type": "IriTemplateMapping",
                "variable": "slug",
                "property": "schema:name",
                "required": true
 }

and event itself includes value for eventName property (mapped in JSON-LD context to schema:name), i think pseudo code above doesn't need that templateVariables assignment and can just use value from the event client intends to create. Actually in current state mapping slug to schema:name but using some other value than one from the payload seems bit confusing to me. Also if we need value of slug different than value of schema:name property, UC5 should also have a way to provide it, which means same code should still work just fine.

Given above we could combine snippets specific to UC5 and UC5.1 into something like

const collection = client.get("http://example.com")
    .getApiDocumentation()
    .getEntryPoint()
    .getCollection({
      property: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
      object: "http://schema.org/Event"
      })

const operation = collection.getOperationForAction('http://schema.org/CreateAction')
    .thatExpect('http://schema.org/Event')
    .first();

client.invoke(operationWithTargetExpanded, event);

Generic Hydra client (like Herakles.ts) can most likely implement that relying internally on memberTemplate, doing some magic under the hood to streamline discovery of operations directly referenced from the collection and those referenced from template which collection references with memberTemplate. In my opinion this would take the raw JSON structure of the collection further apart from the interface provided by the client. Taking approach proposed in this PR for me keeps the JSON representation and interface provided by generic hydra client more aligned.

In next days I will regularly respond to all discussions on this PR to have it moving forward before our next telecon!


Review status: all files reviewed at latest revision, 6 unresolved discussions.


Comments from Reviewable

@alien-mcl
Copy link
Member

Well - in my opinion actions won't resolve that issue you've pointed. Action does not tell the client on how to build a resulting request - which details should go into the IRI template and which into the body.

Indeed, client shouldn't need prior knowledge telling him to expand the operation with details or not, but I'm worried that there will be situations when this snipped:

client.invoke(operation, event);

will be enough - operation would have an IRI template that expects variables provided from outside of the event - what would client do in that scenario?

I believe we've touched an issue we had a very brief chat on before - operation (or action, doesn't matter) is neither only it's body nor it's URL(template) - it's both (or even more for other protocols).
Either operation or action should have a complete description on how to build a proper request, which is missing here.

I aknowledge actions to give some semantic hints to the client - in that scenario operation would be a mere request description, but both still lack a complete knowledge of how the request needs to be created.


Review status: all files reviewed at latest revision, 6 unresolved discussions.


Comments from Reviewable

@tpluscode
Copy link
Contributor

i think pseudo code above doesn't need that templateVariables assignment and can just use value from the event client intends to create

I do not agree. With a URI template I don't think we should assume that the mappings are derived from the actual request representation. They could and the actual event would be used to fill in the template

var newEvent = {};

/* ... */

const operationWithTargetExpanded = operation.expandTarget(newEvent);
client.invoke(operationWithTargetExpanded, newEvent);

But from the client (library) perspective I think these should be kept separate.


Review status: all files reviewed at latest revision, 8 unresolved discussions.


drafts/use-cases/0.intro.md, line 61 at r3 (raw file):

        },
        "target": {
            "@id": "hydra:target",

So we want this to be "@reverse": "hydra:operation"?


drafts/use-cases/1.1.security-considerations.md, line 35 at r3 (raw file):

This just makes the benefits from action event less tempting

There is one good benefit. Instead of minting properties like hydra:search, the API can group all possible actions (:tada:) together. A client may not understand the semantics if they use something unexpected (aka not schema.org) but the implementation will be simpler to present the possible options to the client.

BTW. How would you pick the operation matching a desired protocol?

I'd say this is outside of the scope of the API description.


drafts/use-cases/1.entry-point.md, line 94 at r3 (raw file):

Previously, lanthaler (Markus Lanthaler) wrote…

For embedded actions/operations it is, yeah. But it may be fine as they would only be used rarely. @elf-pavlik could you please add an example illustrating how this would work in a ApiDocumentation? We would likely support two cases there: a) explicit target and b) implicit target that depends, e.g., on a resource's class

Oh yeah, this was bugging me. In general we have symmetry between ApiDocumentation and inline affordances

  • operation => supportedOperation
  • property => supportedProperty

Actions looked to me like an inline-only feature...


drafts/use-cases/5.1.creating-event-with-put.md, line 67 at r1 (raw file):

Previously, lanthaler (Markus Lanthaler) wrote…

Yes. Pavlik already replaced it's need for PUTs here. We could do the same for GETs by adding the following action

    {
        "@type": "schema:DiscoverAction",
        "title": "Directly access a member of the collection (if it exists)",
        "operation": {
            "@type": "Operation",
            "method": "GET",
            "target": {
                "@type": "IriTemplate",
                "template": "http://example.com/api/event{/slug*}",
                "variableRepresentation": "BasicRepresentation",
                "mapping": [
                    {
                        "@type": "IriTemplateMapping",
                        "variable": "slug",
                        "property": "schema:name",
                        "required": true
                    }
                ]
            }
        }
    }

Good one! Another reason to like actions where they help us reduce the overall number of concepts (other being hydra:search)


drafts/use-cases/5.1.creating-event-with-put.md, line 28 at r3 (raw file):

getOperationsForAction()

👍


drafts/use-cases/5.1.creating-event-with-put.md, line 33 at r3 (raw file):

Previously, lanthaler (Markus Lanthaler) wrote…

I agree with Pavlik that the application using Heracles should provide the property and not know anything about the variable name as it is an implementation detail that may change at any time.

Well, both can change 🙂. But neither is out-of-bounds so there is not issue with allowing either. After all this information comes from the template mappings.

Still, I don't understand why two value concatenated into one string. What if one was to have spaces? :) And full URL should be used (or possibly proper JSON-LD)

{
  "http://schema.org/name": [
    { "@value": "meeting" },[
    { "@value": "with will" }
  ]
}

drafts/use-cases/7.searching-events.md, line 19 at r1 (raw file):

Previously, tpluscode (Tomasz Pluskiewicz) wrote…

Ah yes, what I commented above. Would see it more like

var operation = client.get(string).getActionOfType(string).operation

Actually, I like Markus' suggestion above better.


drafts/use-cases/7.searching-events.md, line 72 at r3 (raw file):

        }
    ],
    "action": {

Yes! Kill it, kill it 🔥

Why not just remove search and memberTemplate from the vocabulary with this very PR... (if it hasn't been done yet)


Comments from Reviewable

@tpluscode
Copy link
Contributor

Review status: all files reviewed at latest revision, 8 unresolved discussions.


drafts/use-cases/0.intro.md, line 61 at r3 (raw file):

Previously, tpluscode (Tomasz Pluskiewicz) wrote…

So we want this to be "@reverse": "hydra:operation"?

Also, I notice that there is a schema:target too. This can be confusing


drafts/use-cases/7.searching-events.md, line 19 at r1 (raw file):

Previously, tpluscode (Tomasz Pluskiewicz) wrote…

Actually, I like Markus' suggestion above better.

Sorry about going back and forth but it occurred to me that maybe the client may be interested in properties of the action (a human description?). Going straight for the operation can be unintuitive


Comments from Reviewable

@lanthaler
Copy link
Member

I agree with everything Pavlik said. The design might still need a bit of work though (some of which may be out of scope for this PR like a more expressive description of what data an action/operation expects). I'd like to explore even more drastic changes to the client interface by raising the level of abstraction to something like this:

client.usingApi("http://example.com/")
    .findCollectionWith({
      property: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
      object: "http://schema.org/Event"
      })
    .invoke('http://schema.org/CreateAction')
    .whichExpects('http://schema.org/Event')
    .withData(event)
    .getResult();

We should keep an eye on the verbosity the split of operations into actions and operations entails.


Review status: all files reviewed at latest revision, 8 unresolved discussions.


Comments from Reviewable

@alien-mcl
Copy link
Member

API changes, even drastic are not the issue here. These are relatively easy to implement, including the example above.
The issue is the design, that lacks that very single line in your example:

.withData(event)

Neither suggested actions nor current operations are not oriented in that direction.


Review status: all files reviewed at latest revision, 8 unresolved discussions.


Comments from Reviewable

@elf-pavlik
Copy link
Member Author

Review status: all files reviewed at latest revision, 8 unresolved discussions.


drafts/use-cases/0.intro.md, line 61 at r3 (raw file):

Previously, tpluscode (Tomasz Pluskiewicz) wrote…

Also, I notice that there is a schema:target too. This can be confusing

In latest version of this PR hydra:operation references hydra:Operation from schema:Action, not any more from hydra:Resource


drafts/use-cases/5.1.creating-event-with-put.md, line 33 at r3 (raw file):

Previously, tpluscode (Tomasz Pluskiewicz) wrote…

Well, both can change 🙂. But neither is out-of-bounds so there is not issue with allowing either. After all this information comes from the template mappings.

Still, I don't understand why two value concatenated into one string. What if one was to have spaces? :) And full URL should be used (or possibly proper JSON-LD)

{
  "http://schema.org/name": [
    { "@value": "meeting" },[
    { "@value": "with will" }
  ]
}

If server uses some value to compose IRI it probably has to URL encode that value


drafts/use-cases/7.searching-events.md, line 72 at r3 (raw file):

Previously, tpluscode (Tomasz Pluskiewicz) wrote…

Yes! Kill it, kill it 🔥

Why not just remove search and memberTemplate from the vocabulary with this very PR... (if it hasn't been done yet)

to remove hydra:search we have to share such proposal with a mailing list, i could follow up with another PR just for that. As for hydra:memberTemplate - if we need it for some 'random access' type of feature we probably should add a Use Case for it first.


Comments from Reviewable

@alien-mcl
Copy link
Member

Review status: all files reviewed at latest revision, 8 unresolved discussions.


drafts/use-cases/7.searching-events.md, line 72 at r3 (raw file):

Previously, elf-pavlik (elf Pavlik) wrote…

to remove hydra:search we have to share such proposal with a mailing list, i could follow up with another PR just for that. As for hydra:memberTemplate - if we need it for some 'random access' type of feature we probably should add a Use Case for it first.

In Heracles.ts there is already an integration test that uses hydra:memberTemplate to bind the collection with the direct member access here.
With this predicate I could attach an operation that sits under the IRI template directly to the collection itself without any additional intermediate beings.


Comments from Reviewable

@lanthaler
Copy link
Member

Yeah, we would need to define that.

@elf-pavlik do you have time do another pass over this, address the feedback and add the examples that have been asked for?


Review status: all files reviewed at latest revision, 6 unresolved discussions.


Comments from Reviewable

@tpluscode
Copy link
Contributor

Review status: all files reviewed at latest revision, 5 unresolved discussions.


drafts/use-cases/5.1.creating-event-with-put.md, line 33 at r3 (raw file):

Previously, elf-pavlik (elf Pavlik) wrote…

If server uses some value to compose IRI it probably has to URL encode that value

This is beside the point and defined in the variableRepresentation


Comments from Reviewable

@elf-pavlik
Copy link
Member Author

I haven't found time in last two weeks to properly consider UC9 Adding existing resources to collections, and other cases where we just want to create relation (link) two resources.
As discussed during the last telecon, in last commit (just pushed) I minimized differences between UC5 and UC5.1 starting with case where both don't require additional slug and rely on using UUID to mint an IRI for new resource. In UC5 server does it on POST, in UC5.1 client does it for PUT.
As long as we only have 'add member to collection' use cases which for action on one resource (the collection) require performing operation on another resource (the member), hydra:memberTemplate seems like working approach. Having other use case which can't rely on hydra:memberTemplate would make clearer the advantage of having distinct action and operation.


Review status: 7 of 9 files reviewed at latest revision, 5 unresolved discussions.


Comments from Reviewable

@elf-pavlik
Copy link
Member Author

Last commit provides new take on UC9, renaming it to "Creating relations between existing resources". It introduces tbd:LinkAction and tbd:UnlinkAction (TBD - to be decided) as generic mechanism to relate two existing resources with specific predicate. This provides another example which proposed in #158 hydra:memberTemplate can't handle and in general trying to create dedicated property to such resources acting as target for operation doesn't seem to make sense.


Review status: 7 of 11 files reviewed at latest revision, 5 unresolved discussions.


Comments from Reviewable

@lanthaler
Copy link
Member

Reviewed 2 of 2 files at r4, 2 of 2 files at r5.
Review status: all files reviewed at latest revision, 5 unresolved discussions.


drafts/use-cases/5.1.creating-event-with-put.md, line 30 at r5 (raw file):

      property: "http://www.w3.org/1999/02/22-rdf-syntax-ns#type",
      object: "http://schema.org/Event"
      })

Indentation is slightly off. That being said, I love this interface.


drafts/use-cases/9.creating-relations-between-existing-resources.md, line 130 at r5 (raw file):

```jsonld
"@id": "https://example.org/api/events/173a6d5b-e9fc-43d7-a19a-215a06d37f31",

Please make this valid JSON-LD, i.e., wrap it in a curly brackets


Comments from Reviewable

@elf-pavlik
Copy link
Member Author

Review status: all files reviewed at latest revision, 7 unresolved discussions.


drafts/use-cases/5.1.creating-event-with-put.md, line 30 at r5 (raw file):

Previously, lanthaler (Markus Lanthaler) wrote…

Indentation is slightly off. That being said, I love this interface.

Indentation fixed!
Yeah, I just copied and pasted the snippet your wrote in one of the comments above 😸


drafts/use-cases/9.creating-relations-between-existing-resources.md, line 130 at r5 (raw file):

Previously, lanthaler (Markus Lanthaler) wrote…

Please make this valid JSON-LD, i.e., wrap it in a curly brackets

Done.


Comments from Reviewable

@tpluscode
Copy link
Contributor

Reviewed 7 of 8 files at r3, 1 of 2 files at r5, 3 of 3 files at r6.
Review status: all files reviewed at latest revision, 6 unresolved discussions.


Comments from Reviewable

@lanthaler
Copy link
Member

This change :lgtm: now. Please raise any remaining concerns you may have. We'll then discuss it in our telecon in two weeks (Pavlik and I are out tomorrow) and decide how to proceed.


Review status: all files reviewed at latest revision, 4 unresolved discussions.


Comments from Reviewable

@alien-mcl
Copy link
Member

Do we have a consensu here? This PR updates existing use cases with new features. We'll have to update the reference client implementation and spec sooner or later to make everything fit altogether.


Review status: all files reviewed at latest revision, 4 unresolved discussions.


Comments from Reviewable

@serialseb
Copy link

Have we progressed on concensus on this?

@alien-mcl
Copy link
Member

To revive this PR, let me attach a diagram of how do I see this matter. In general, I feel that additional predicate action is redundant (as stated earlier) and extending an operation with some features would be enough.
The diagram below adds these elements:

  • returnsHeader - predicate for pointing returned header names
  • expectsHeader - predicate for pointing expected header names
  • target - explicit target of the operation (either Link or TemplatedLink
  • MediaTypedResource - dummy for describing expected/returned resource that is not an RDF class
  • mediaType - predicate for pointing an expected/returned resource's media type
    These elements are changed:
  • returns - range changed from Class to Resource
  • expects - range changed from Class to Resource

hydra 1 1

@elf-pavlik
Copy link
Member Author

sorry everyone for staying silent in last months!

@alien-mcl I will study your diagram in next days.

I also have another use case for 'append only' dataset where updating a resource will require creating new one using specified iri template. As long as we have explicit target it should work.

@alien-mcl alien-mcl mentioned this pull request Jan 30, 2019
@alien-mcl
Copy link
Member

It's great to have you back @elf-pavlik!

As for the use cases, we're going to create a gitbook with use cases and examples so have that one you mention prepared somewhere

@hyprdia hyprdia mentioned this pull request Jun 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants