HydraCG / Specifications

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

CreateAction with HTTP PUT #141

Closed elf-pavlik closed 6 years ago

elf-pavlik commented 6 years ago

5. Creating new resources mentions creating resources with PUT

Solid also supports creating resources with PUT

In Vimeo API review we also find creating resources with PUT https://github.com/HydraCG/Specifications/issues/134#issuecomment-333393649

Last but not least, in open source project, which I currently work on, we also don't use POST and always create new resources with PUT relying on clients generating UUID ( actually https://github.com/ericelliott/cuid)

In use cases Entry Point we find definition of schema:CreateAction using HTTP POST

      {
        "@type": ["hydra:Operation", "schema:CreateAction"],
        "title": "Create new event",
        "method": "POST",
        "expects": "schema:Event"
      }

Challenge for HTTP PUT seems related to not having an @id for the resource which client needs to perform operation on. Most likely we would just have an URI Template, which I see something relevant discussed in #118 (Specifying operations on TemplatedLink objects) and touched in #100 (Describe/ specify how the target IRI for an hydra:operation is resolved).

As for the IriTemplateMapping it seems to require for value of hydra:property an rdf:Property with rdfs:range UUID.

alien-mcl commented 6 years ago

I've spent some time thinking about it. I've ended up with a conclusion that creating a resource is one thing, linking it with another resource (i.e. collection to be specific) is another matter.

Regardless the approach (rich command/action vocabulary or rich relations vocabulary), creating a resource may with POST, but may not end up with adding newly created resource to the collection. This is how POST works - we send a resource for processing, but we don't really know on what will happen. Situation with PUT is a bit better - hierarchy of resources expressed with segments in the resource's URL may imply that the putted resource will be added to the collection - stil it's not a mandatory behavior. Anyway, what if we want to add to the collection a resource of which URL is not related to the target collection in any way (i.e. URL of a person we want to add as a friend)?

Finally, I've ended up with something like this:

0. Begin
1. Do I know the IRI of the resource I create?
   If yes, go to 4, otherwise go to 2.
2. Is there a POST operation available?
   If yes, go to 3, otherwise go to 7.
3. POST new resource to the operation pointed URL.
   Obtain a Location header and assigned it to the resource's IRI.
   Go to 6.
---
4. Is there a PUT operation available?
   If yes, go to 5, otherwise go to 7.
5. Assign the URL I create to the resource's IRI and PUT the resource to that URL.
---
6. LINK the resource to the designated target resource (i.e. a collection)
   using a desired relation.
   Type of the relation "describing" semantically as a collection concluding
   is a subject for discussion.
7. Abort, unable to perform action.
8. End

Steps 1-3 are related to creating a resource if we don't know on how to create IRI of the resource being created. Steps 4-5 are related to creating a resource assuming we know on how to created the IRI mentioned. Step 6 is actually an operation that "adds" newly created resource to the collection - this is the only operation that should make the client sure of what will happen. Please not that only step 2 (which may be treated as a fallback for dumb clients) is not idempotent. What do you think about that?

lanthaler commented 6 years ago

Please keep in mind that POST != create. From the spec

The POST method requests that the target resource process the representation enclosed in the request according to the resource's own specific semantics.

If your snippet above describes a specific API, that's fine. If it describes the client's behavior, it is not as it simply can't infer the server's behavior (semantics) by just looking at the HTTP methods.

elf-pavlik commented 6 years ago

I think CreateAction with HTTP PUT makes an interesting example of operation which requires IRI other than the resource which advertises it. It seems in some ways similar to hydra:search which range includes hydra:IriTemplate.

@lanthaler since hydra:Operation doesn't provide a way to specify hydra:IriTemplate it seems that we may not use schema:CreateAction with both HTTP POST and HTTP PUT. BTW since we consider recommending http://schema.org/docs/actions.html we may also want to have some explanation about http://schema.org/target

Also hydra:search doesn't work as an operation so one shouldn't look for schema:SearchAction. Having something like schema:target which range includes IRI and hydra:IriTemplate (and defaults to IRI of the resource advertising the action) we could use schema:CreateAction with either POST or PUT and also treat a search as schema:SearchAction

tpluscode commented 6 years ago

hierarchy of resources expressed with segments in the resource's URL may imply that the putted resource will be added to the collection

Sorry to say, that is completely out of place. URL structures should imply nothing. It's just an identifier.

tpluscode commented 6 years ago

hydra:Operation doesn't provide a way to specify hydra:IriTemplate

So maybe let's work on that. Is there a reason why it shouldn't?

tpluscode commented 6 years ago

A bit on the side, I remember thinking about minting URIs for operations (mostly PUT which is discussed here). My idea was to simply combine the parameters of a hypothetical URI Template and the one of the operation.

For example, if the client was to PUT /article/{title} that title variable could also be part of the operation's parameters. That way we have a uniform way to handle user input (think generating a <form>). The title property is just another field along with other stuff that go in the request body such as publishDate, abstract, author, etc.

elf-pavlik commented 6 years ago

For use cases I would like to use it for, I only need a way to specify that variable in a template comes as unique identifier UUID, CUID, GUID

For example, if the client was to PUT /article/{title} that title variable could also be part of the operation's parameters

I worry that in use case you mention, when later updating a title one might also expect IRI to change as well.

tpluscode commented 6 years ago

I worry that in use case you mention, when later updating a title one might also expect IRI to change as well.

No because the operation on an existing resource will be different. You would be operating on a concrete URI.

But that's not the essence of what I meant. The logic is that the template's variables would be treated just as any other operation parameter. Whether that same variable exists in the operation or not. If #118 was agreed upon that could become something to work on in Heracles.

elf-pavlik commented 6 years ago

I think hydra:IriTemplateMapping (example 15) and hydra:SupportedProperty (example 8) already work in quite similar similar way. At the same time I think we need to have them distinct, for example I would have hydra:IriTemplateMapping for UUID but I wouldn NOT want to include that UUID as hydra:SupportedProperty. At the same time we may want to have a way that if resource has both hydra:IriTemplateMapping and hydra:SupportedProperty for dc:title, both expect a value from 'expected' resource.

tpluscode commented 6 years ago

I don't think I understood your comment ;)

elf-pavlik commented 6 years ago

The logic is that the template's variables would be treated just as any other operation parameter.

In your example of dc:title, it would appear in both hydra:IriTemplateMapping and hydra:SupportedProperty in some kind of foo:Article a hydra:Class. And the operation would have [] hydra:expects foo:Article. The operation itself would not directly have any 'parameter' in some way related to dc:title. Let's maybe all try to put more JSON-LD snippets in our comments to show more clearly what we have in mind?

tpluscode commented 6 years ago

I think you got it just the way I had in mind

alien-mcl commented 6 years ago

Please keep in mind that POST != create. From the spec

I know. The closest is PUT, but it requires quite a knowledge from the client (URL).

hierarchy of resources expressed with segments in the resource's URL may imply that the putted >>resource will be added to the collection

Sorry to say, that is completely out of place. URL structures should imply nothing. It's just an identifier.

In our cases - that's true. There are specs that indeed a URL hierarchy actually matters.

hydra:Operation doesn't provide a way to specify hydra:IriTemplate

So maybe let's work on that. Is there a reason why it shouldn't?

Agreed - I strongly support templated operations. I tried to use what's available in the spec in my URSA server/client solution, but the outcome is not very "healthy".

For example, if the client was to PUT /article/{title} that title variable could also be part of the >operation's parameters.

Not a very good example, as indeed title could vary in time causing the URL to change, but with a property mapped as unique identifier, client could take an advantage of the templated operations. This should be an extension to the core Hydra anyway - I don't see Hydra defining what a unique identifier is. Implementations can rely on owl:inverseFunctionalProperty, but from the template point of view it should be just another parameter. Only difficulty I see is that currently the spec says the the Iri template parameter is of a given property from the server point of view (i.e. server maps this parameter to that property) - it doesn't imply that client should use value of that very property when creating Iris.

tpluscode commented 6 years ago

Please fix the formatting in your last post @alien-mcl

asbjornu commented 6 years ago

If more of us could be made owners or administrators of this repository, we could help each other edit comments to improve formatting and such. I have itching fingers for things like these and would love to help if I had access to. ;-)

alien-mcl commented 6 years ago

I'm trying to implement that case and I experience serious issues related on how to do this. I was thinking about a situation where I have two collections of events of type schema:Event and people of type schema:Person. Every single schema:Person can have a schema:perfomerIn relation with an event, I see no real possibility of implementing a situation when a client wants to PUT a schema:Event to /api/people/1/perfomerIn without instructing it on how to create a proper URL, which would be in this case /api/people/1/perfomerIn/2 (I wanted to PUT /api/events/2 to create a </api/people/1> schema:perfomerIn </api/events/1>). Indeed server could provide all possible PUT URLs of events, but this is not a good approach. It's fine with closed set of values, but open sets are no good in that situation. Any ideas?

asbjornu commented 6 years ago

@alien-mcl: Why do you need to use PUT? Isn't this discussion only about being able to use PUT in addition to POST, not requiring PUT? If POST works better for your scenario (which it sounds like it does), then why not use POST?

elf-pavlik commented 6 years ago

I think we should go with one step at a time, while we have dedicated issue for #134 here we can start with a UC#5 Creating a new event and just use PUT instead of POST. Looking at UC#1 Entry point, as I suggested in https://github.com/HydraCG/Specifications/issues/3#issuecomment-336635276 the definition of action should stay almost the same. Currently we have

{
  "@context": "/api/context.jsonld",
  "@id": "/api",
  "@type": "hydra:EntryPoint",
  "collection": [
    {
      "@id": "/api/events",
      "title": "List of events",
      "@type": "hydra:Collection",
      "manages": {
        "property": "rdf:type",
        "object": "schema:Event"
      },
      "operation": {
        "@type": ["hydra:Operation", "schema:CreateAction"],
        "title": "Create new event",
        "method": "POST",
        "expects": "schema:Event"
      }
    }
  ]
}

If service chooses to use PUT not POST to create, it would have something like

{
  "@context": "/api/context.jsonld",
  "@id": "/api",
  "@type": "hydra:EntryPoint",
  "collection": [
    {
      "@id": "/api/events",
      "title": "List of events",
      "@type": "hydra:Collection",
      "manages": {
        "property": "rdf:type",
        "object": "schema:Event"
      },
      "action": {
        "@type": ["hydra:Operation", "schema:CreateAction"],
        "title": "Create new event",
        "method": "PUT",
        "expects": "schema:Event",
        "targetTemplate": {
          "@type": "hydra:IriTemplate",
          "hydra:template": "/api/events/{?uuid}",
          "hydra:mapping": {
            "hydra:variable": "uuid",
            "hydra:property": "id:uuid",
            "hydra:required": true
          }
        }
      }
    }
  ]
}

Once we have at least one possible solution for simple case like this, we can see if it still works with more complex case (like relating existing resources), but I see benefits with starting from simple case.

lanthaler commented 6 years ago

@lanthaler since hydra:Operation doesn't provide a way to specify hydra:IriTemplate it seems that we may not use schema:CreateAction with both HTTP POST and HTTP PUT

I realize it is not properly documented but the intention was always that operations would work on IriTemplates just as they work on resources... otherwise things like hydra:search wouldn't work.

tpluscode commented 6 years ago

Isn't hydra:search a link?

Regardless, it's not clear indeed. I think the use of templates with operations has come up a few times and I never realised what you just wrote :)

tpluscode commented 6 years ago

As a followup to the comment above, here are Pavlik's snippets rewritten by attaching the operation to IRI template.

Nothing changes if the operation is POST on the collection itself:

{
  "@context": "/api/context.jsonld",
  "@id": "/api",
  "@type": "hydra:EntryPoint",
  "collection": [
    {
      "@id": "/api/events",
      "title": "List of events",
      "@type": "hydra:Collection",
      "manages": {
        "property": "rdf:type",
        "object": "schema:Event"
      },
      "operation": {
        "@type": ["hydra:Operation", "schema:CreateAction"],
        "title": "Create new event",
        "method": "POST",
        "expects": "schema:Event"
      }
    }
  ]
}

If service chooses to use PUT not POST to create, it would link to the resource to PUT to and have the operation on that

{
  "@context": "/api/context.jsonld",
  "@id": "/api",
  "@type": "hydra:EntryPoint",
  "collection": [
    {
      "@id": "/api/events",
      "title": "List of events",
      "@type": "hydra:Collection",
      "manages": {
        "property": "rdf:type",
        "object": "schema:Event"
      },
      "hydra:addMember": {
        "@id": "/api/events/new",
        "operation": {
          "@type": ["hydra:Operation", "schema:CreateAction"],
          "title": "Create new event",
          "method": "PUT",
          "expects": "schema:Event"
        }
      }
    }
  ]
}

If the IRI of the resource used to create isn't known an IRITemplate can be used without changing the above much:

{
  "@context": "/api/context.jsonld",
  "@id": "/api",
  "@type": "hydra:EntryPoint",
  "collection": [
    {
      "@id": "/api/events",
      "title": "List of events",
      "@type": "hydra:Collection",
      "manages": {
        "property": "rdf:type",
        "object": "schema:Event"
      },
      "hydra:addMember": {
        "@type": "IriTemplate",
        "template": "/api/events/{slug}",
        "mappings": [{
          "variable": "slug"
        }],
        "operation": {
          "@type": ["hydra:Operation", "schema:CreateAction"],
          "title": "Create new event",
          "method": "PUT",
          "expects": "schema:Event"
        }
      }
    }
  ]
}

The only difference is that instead of a concrete "@id", the target is an hydra:IrITemplate. To perform the request first the template needs to be resolved.

tpluscode commented 6 years ago

To address the issue of how the client "knows" that the said PUT operation actually adds members to the parent collection, there are two hints: "schema:CreateAction" and the hypothetical link relation hydra:addMember.

In addition, as I mentioned in the call, we could have extra metadata on the operation itself. Something like:

{
  "@type": ["hydra:Operation", "schema:CreateAction"],
  "hydra:sideEffects": [{
    "@type": "hydra:AddLinkEffect",
    "property": "hydra:member",
    "subject": "/api/events"
  }]
}

Something like that? A side-effects block which can be used as an extension point for goal-oriented clients to describe how any operation affects other resources. In this example the AddLinkEffect (excuse poor naming) could describe the a /api/events hydra:member _:new_member triple will be created.

Similarly it could describe that a DELETE operation on resource will remove it from other collections. Going back to the Vimeo example we could have

{
  "@id": "/users/elfpavlik/likes/144522067",
  "operation": {
    "@type": ["hydra:Operation", "schema:DeleteAction"],
    "hydra:sideEffects": [{
      "@type": "hydra:BreakLinkEffect",
      "property": "hydra:member",
      "subject": "/users/elfpavlik/likes"
    }, {
      "@type": "hydra: BreakLinkEffect",
      "property": "hydra:member",
      "subject": "/videos/144522067"
    }]
  }
}

Such extension point would allow various built-in and API-specific ways to describe what the operation does.

asbjornu commented 6 years ago

@tpluscode: Thanks for the elaborate examples, they help (at least me) when discussing this. Is there any particular reason why "hydra:addMember" has an @id, but none of the other operations in your examples?

Also, why are there seemingly so many different ways to embed operations? Shouldn't they all go into an operation array?

In relation to the client understanding what an operation does, I was under the impression that @type in combination with expects was all that's needed to decipher the operation semantics? If @type states schema:CreateAction and expects is set to schema:Event, isn't it obvious that the operation creates events (within the current scope, being the hydra:Collection)? Do we need to complicate this further?

Sorry, but I don't fancy the hydra:BreakLinkEffect proposal, as it sounds way too finegrained to belong in the core vocabulary. Are side effects something we need to tackle in version 1.0 of Hydra? Isn't that something we can figure out whether is required and add on along with a plethora of other things we're guaranteed to not cover in 1.0?

Lastly, what's the difference between the properties prefixed with hydra: (such as hydra:addMember) and those who doesn't (such as expects)? I assumed both of these fell under the Hydra namespace and thus should preferably be the default (removing the need for the hydra: prefix)?

To unify the different examples given above, this is how I would want to express the three different create operations:

{
  "@context": "/api/context.jsonld",
  "@id": "/api",
  "@type": "hydra:EntryPoint",
  "collection": [
    {
      "@id": "/api/events",
      "title": "List of events",
      "@type": "hydra:Collection",

      // Renamed "manages" to "contains" and made it a string instead of object, for simplicity.
      "contains": "schema:Event",

      // Single "operation" array to contain all operations regardless of their semantics.
      "operation": [
        {
          // All operations can be uniformly identified by their @id.
          "@id": "/api/events/new",
          "@type": ["hydra:Operation", "schema:CreateAction"],
          "title": "Create new event",
          "method": "POST",
          "expects": "schema:Event"
        }, {
          "@id": "/api/events/new",
          "@type": ["hydra:Operation", "schema:CreateAction"],
          "title": "Create new event",
          "method": "PUT",
          "expects": "schema:Event",

          // If the target is a string, it's implicitly of @type: '@id'. I have no idea if this is possible with JSON-LD, but this flexibility would be neat and make the format simpler.
          "target": "/api/events/06c31878411c45ffa0996c45a3a58eb1",
        }, {
          "@id": "/api/events/new",
          "@type": ["hydra:Operation", "schema:CreateAction"],
          "title": "Create new event",
          "method": "PUT",
          "expects": "schema:Event",

          // If the target is an object, it will most likely always be a 'hydra:IriTemplate', possibly making the @type property automatically inferred and obsolete (I hope)?
          "target": {
              "@type": "hydra:IriTemplate",
              "template": "/api/events/{?uuid}",

              // No 'hydra:' prefix if possible.
              "mapping": {
                "variable": "uuid",
                "property": "id:uuid",
                "required": true
              }
          },
        }
      ]
    }
  ]
}

With this uniformity, it's pretty easy to write a client, since all operations can be handled the same way. You just need to see if there's a target property, and if it is, use it as the URI (or as a template to build the URI) to perform the operation against.

Please don't hesitate to out all the errors I've made above. 😃

NOTE: I'm not saying a collection will actually have three different ways to create members, I'm just including all variants so they can be compared in close proximity.

elf-pavlik commented 6 years ago

To address the issue of how the client "knows" that the said PUT operation actually adds members to the parent collection, there are two hints: "schema:CreateAction" and the hypothetical link relation hydra:addMember.

I would really like to find a way that client will discover specific action in the same way, and description of the action will instruct it what operation (and on which resource) it has to perform to accomplish given action. IMO client shouldn't have to understand anything like hydra:addMember in addition to schema:CreateAction just because PUT on another resource handles this action instead of POST on the same resource (the collection).

In approach where I suggested, we could define

hydra:operation rdfs:subPropertyOf hydra:action

Which makes hydra:operation a more specific action, where the subject in the statement using it acts also as a target of that operation.

In JSON-LD the @context could in addition include alias

"target": { "@reverse": "hydra:operation" }

We could also consider optional

This way, client will just need to:

  1. look at all the instances of hydra:Operation which resource references via hydra:action (which automatically includes all the resources referenced by more specific hydra:operation).
  2. select desired action based on @type, hydra:expects and other possible criteria
  3. perform operation (handle action) based on hydra:method and target identified by:
    • reverse direction of hydra:operation if resource used more specific hydra:operation
    • target (reverse use of hydra:resource) providing IRI for operation if resource used broader hydra:action
    • hydra-pr:targetTemplate providing hydra:IriTemplate based on which client can construct IRI which will serve as target of the operation.
tpluscode commented 6 years ago

@asbjornu:

Is there any particular reason why "hydra:addMember" has an @id

Indeed there is. This is not an operation. It's a link. In triples it would be represented as </api/events> hydra:addMember </api/events/new>. I realise that the I chose the predicate poorly. The intention was for a link between the collection and the resource used to created new members. The target in the terminology you use.

So again, the target of the operation is always the parent in JSON-LD. The subject in the ?subject hydra:operation ?operation triple. Hence, no need for an explicit target property.

If @type states schema:CreateAction and expects is set to schema:Event, isn't it obvious that the operation creates events (within the current scope, being the hydra:Collection)? Do we need to complicate this further?

Maybe we don't but I do see the value in letting the client know that the created event will become a member of a given collection. This way you can, optionally, describe side effects on other resources shall you need to.

Sorry, but I don't fancy the hydra:BreakLinkEffect proposal, as it sounds way too finegrained to belong in the core vocabulary

I agree. You're right that the core should only include an abstract term. An extension point for implementation by specialised vocabularies. I just wanted this as an illustration of how the idea can be executed.

This is also something not crucial for a generic client. It could safely ignore this description and still be able to successfully perform the operation.

So maybe this should probably be the deciding factor in any argument whether something belongs to the core vocabulary - is it necessary for a generic client. Anything else should be an extension.

Lastly, what's the difference between the properties prefixed with hydra: and those who doesn't?

No difference I think. However we're accustomed that we don't prefix the common terms. I prefer to add prefix to something that isn't officially in the vocabulary.

With this uniformity, it's pretty easy to write a client

We already have this uniformity. The target is always the parent. @id or hydra:templated to be filled in.

tpluscode commented 6 years ago

@elf-pavlik are you sure that your proposal is simple?

I still don't understand the distinction between operation and action. This is pure confusion.

Also, the steps are more elaborate than I think you let us believe ;). Some observations to consider:

instances of hydra:Operation which resource references via hydra:action

no idea what that means

perform operation (handle action)

do you see how these overlapping terms are just a distraction?

reverse direction of hydra:operation if resource used more specific hydra:operation

again, more complicated than "the target is the parent. period"

hydra-pr:targetTemplate providing hydra:IriTemplate

ditto, if the parent is a template use that. and no need for additional core term

elf-pavlik commented 6 years ago

again, more complicated than "the target is the parent. period" [...] ditto, if the parent is a template use that. and no need for additional core term

I would prefer that we don't discuss it in terms of some specific framing of JSON-LD and keep in mind that people may prefer to use Turtle or any other serialization. I'll try to stick to Statement (Triple or Quad) and s, p, o in all further comments!

instances of hydra:Operation which resource references via hydra:action

no idea what that means

all the operations matching

</some-resource> hydra:action ?operation

I still don't understand the distinction between operation and action. This is pure confusion.

As discussed in #3 currently hydra:operation implies that target of an Operation ("target"" { "@reverse": "operation" }) while schema:potentialAction does not act as reverse of `schema:target. This allows resources in schema.org to reference instances of schema:Action which have schema:target other than the resource itself. I would like us to consider also providing such option in Hydra.

Is there any particular reason why "hydra:addMember" has an @id

Indeed there is. This is not an operation. It's a link. In triples it would be represented as </api/events> hydra:addMember </api/events/new>. I realise that the I chose the predicate poorly. The intention was for a link between the collection and the resource used to created new members. Thetarget` in the terminology you use.

Does it mean that in UC#1 Entry point we would have to add statement </api/events> hydra:addMember </api/events> ?

{
      "@id": "/api/events",
      "title": "List of events",
      "@type": "hydra:Collection",
      "manages": {
        "property": "rdf:type",
        "object": "schema:Event"
      },
+     "hydra:addMember": "/api/events",
      "operation": {
        "@type": ["hydra:Operation", "schema:CreateAction"],
        "title": "Create new event",
        "method": "POST",
        "expects": "schema:Event"
      }
    }

In approach I propose we could simply reuse schema:AddAction instead having to define hydra:addMember. But now I notice that if we would have

</api/events> schema:potentialAction [
  a hydra:Operation, schema:AddAction, schema:CreateAction ;
  schema:target </api/events/new>
] .

schema:AddAction should apply to </api/events> but schema:CreateAction should apply to </api/events/new> so we get ugly ambiguity here. We could still have

</api/events> schema:potentialAction [
  a hydra:Operation, schema:AddAction ;
  schema:target </api/events/new>
] .
</api/events/new> hydra:operation [
  a hydra:Operation, schema:CreateAction
] .
elf-pavlik commented 6 years ago

@tpluscode in your snippets the instance of hydra:Resource or hydra:IriTemplate on object position in a statement with hydra:addMember, advertised only single operation. In case when that resource or template advertises (references via hydra:operation) more than one instances of hydra:Operation, how the client knows which of those operations to choose?

It seems like clients needs to follow those two steps 1) starting from a collection follow hydra:addMember to discover a resource or template handling adding members to that collection 2) on that discovered resource or template follow all the hydra:operation and select the one with with [] rdf:type hydra:Operation, schema:CreateAction .

This seems pretty similar to what I have in mind 1) starting from a collection follow schema:potentialAction and select the one with [] rdf:type schema:AddAction . 2) from selected operation follow schema:target (or hydra:operation but in reverse direction) to discover resource or template handling that action 3) on that discovered resource or template follow all the hydra:operation and select the one with with [] rdf:type hydra:Operation, schema:CreateAction .

so the last steps look exactly the same, it only differs on how client discovers the resource or template which handles intended action, and if we specify intended action using schema:Action (rdfs:Class) or hydra:Link (rdf:Property). I think we could try to see how those two approaches would work with #134

What I like about those both approaches, they don't rely on particular choice of HTTP method in the operation, which I understood @alien-mcl explores in https://github.com/HydraCG/Heracles.ts/pull/18 IMO we should only rely statements using terms from Hydra vocab and something like schema.org actions and don't try to infer things from some particular choice of HTTP methods.

tpluscode commented 6 years ago

I'll try to stick to Statement (Triple or Quad) and s, p, o in all further comments!

Sort of agree because remember, not all readers here will be RDF-savvy.

I would like us to consider also providing such option in Hydra.

It is there already in the form of adding operations to linked resources.

Does it mean that in UC#1 Entry point we would have to add statement </api/events> hydra:addMember </api/events> ?

I don't think that would be necessary because you already have the PUT operation with appropriate type. And again, that predicate was purely for the example's sake. We could define one in hydra (akin hydra:search) but it could also be any other API-specific link because it has limited semantics. What the client is actually interested in are the operations.

In case when that resource or template advertises more than one instances of hydra:Operation, how the client knows which of those operations to choose?

This is a good question but maybe a little vague. The real question is what are the client's requirements expectations. For starters, an operation already contains some information: the @type(s), the expects, the method.

I wouldn't want to cram much more in the core specification. Any more elaborate metadata should IMO be outside of our scope and become some extension of Hydra Core

It seems like clients needs to follow those two steps

Actually, I was thinking of a single step albeit requiring recursion:

  1. Find schema:CreateAction in any recursively linked resource but only operation which expects: schema:Event. In SPARQL you'd have two pattern:

    `?operation rdf:type schema:CreateAction ;
                hydra:expects schema:Event`

See how I drafted that in PR #143

IMO we should only rely statements using terms from Hydra vocab and something like schema.org actions and don't try to infer things from some particular choice of HTTP methods.

Ver much so! The HTTP method is just an implementation detail and we shouldn't encourage

lanthaler commented 6 years ago

What is this issue about at this point? What are the questions we need an answer for to resolve it?

elf-pavlik commented 6 years ago

After merging #143 now we have UC#5.1 Creating event with PUT

I think we can close this one and continue work in other issues, for exampe: