RE: An updated draft of the schema.org/Action proposal

On Friday, January 24, 2014 2:24 AM, Sam Goto wrote:
>> On Wed, Nov 27, 2013 at 6:37 AM, Markus Lanthaler wrote:
>> On Tuesday, November 26, 2013 7:39 PM, Sam Goto wrote:
>>> On Wed, Nov 20, 2013 at 8:40 AM, Markus Lanthaler wrote:
>>>> Hmm... you changed "expects" to take a SupportedProperty instead of a
>>>> Class which results in a asymmetry with "returns" which still takes a
>>>> Class.

[...]

>>>> Furthermore, SupportedProperty has no "property" property anymore but
>>>> you use "name" to specify it - which is a string and could be anything.
>>>
>>> SupportedProperty extends from Property, so it doesn't need to take one.
>> 
>> This doesn't make any sense to me as it makes it completely impossible to
>> reuse any of the existing Schema.org properties (or any property in another
>> vocabulary for that matter).
> 
> Got it. So instead of referring to the property via the "name" (e.g.
> "description"), you use URI identifiers instead (e.g.
> http://schema.org/description) which buys you precision

Exactly

> in exchange for verbosity?

Not necessarily. At least not in JSON-LD:

  {
    "@context": {
      "@vocab": "http://schema.org/",
      "property": { "@type": "@vocab" }
    },
    "property": "description"
  }

expands to

  {
    "http://schema.org/property": {
      "@id": "http://schema.org/description"
    }
  }

and thus doesn't introduce additional verbosity.


>>>>> In most cases a human-readable label to be read in a dynamically
>>>>> generated UI or documentation.
>>>>
>>>> I'm not sure I like this design. The reason is that most developers
>>>> think in terms of (resource) classes. This is pretty apparent even if
>>>> you just look at three arbitrary Web APIs:
>>>>
>>>> Google+: https://developers.google.com/+/api/latest/
>>>
>>> I am/was actively involved in most of these APIs :)
>> 
>> Then your change surprises me even more as the documentation uses
>> exactly the structure I'm proposing. For example (citing [1]):
> 
> You are right. I think that thinking in terms of resources (rather than
> RPCs) gets lots of things simplified. Specifically, the following:
> 
> - collections: which allows you to do things like (a) searching for
>   resources and (b) creating/acting on resources even before they exist
> - resource hopping: moving from one resource to another and performing
>   operations in the right context
> - dynamic operations: as resource state changes, operations available in
>   them are now made possible to change

Right. Furthermore, it integrates much better with the architecture of the Web in general.


> Here are a few demos I'm writing to validate this model with a few real
> world use cases that are relevant:
> 
> http://code.sgo.to/crawler/yaap.html#url=http://code.sgo.to

Wow! Cool stuff! Are these documents available somewhere to download? I mean in the form of a single archive or a Git/SVN/whatever repository? That would make it simpler for me to go through all the examples.

I know the ActionHandler stuff is there for Android support etc. but wouldn't it be possible to avoid it (as discussed previously) and thus eliminate one level of nesting?


[...]

>>> Most importantly, with "expects" and "returns" being schema.org properties
>>> they can evolve incrementally over time to take other types (e.g. Class),
>>> so hopefully we can cross this bridge when we get to it.
>>
>> I really don't understand the reasons for the deviation of the model Hydra
>> or (Resource Shapes) follow. Are you concerned about the complexity? I
>> think it makes things much easier to understand a allows reuse which is
>> impossible if a just a set of SupportedProperties is used.
>>
>> Have you had the chance to take a look at [2]? Would love to hear your
>> opinions?
> 
> I did, yes, thank you that's super helpful.

Great

 
> I think SupportedClasses make sense, but I'm still unhappy with
> complexity and verbosity of large API specifications when you get into
> the "nested requirements case" (which gmail is addressing via a "path-
> like" syntax with things like "review.reviewBody" to refer to the
> "reviewBody" property inside "review") ... Take food orders as an
> example:
> 
> http://code.sgo.to/crawler/yaap.html#url=http://code.sgo.to/restaurants/123/orders

Good point. The question here, I think, is really whether you want to embrace linked data principles or not. If you do, you are able to define your classes with their supported properties somewhere and then reference them from properties by using their URLs. Obviously clients then need to fetch those documents on the fly (or cache them locally). If you want/need to define everything inline it becomes trickier. A possibility would be to create new classes on the fly which flatten these structures but that's not very elegant either. But honestly, I don't think this nesting is really a problem. It's quite symmetric and developers are used to these things already. In HTML, e.g., you create similar nestings all the time (think of list with sub-lists e.g.)


> It ends up with a quite large/verbose/complex set of requirements and
> expectations, and I'm trying to find ways to compress that into
> something cleaner for the simple case.
> 
> Here is another example that I explored a bit deeper:
> 
> http://code.sgo.to/crawler/yaap.html#url=http://code.sgo.to/hotels/123

Nice, concise example (the operation type should be something like BookAction though, not SearchAction).


> One idea is to take advantage of the fact that most times you want to
> express whether a property is required or not (rather things like
> cardinality, min/max values, etc). For example, if we (a) break down
> http://schema.org/SupportedClass.supportedProperty-ies into
> requiredProperty and optionalProperty and (b) let it take
> http://schema.org/Property (in addition to
> http://schema.org/SupportedProperty, which no longer holds whether the
> property is required or not), it avoids having to instantiate a new
> SupportedProperty.
> 
> In the complex case (e.g. requirements on cardinality, min/max values,
> enumerations, etc), requiredProperty and optionalProperty may still
> take a SupportedProperty in case it needs to be more specific.

How would you know what it is? Go and dereference all of them and check their types?


> Here is what this
> http://code.sgo.to/crawler/yaap.html#url=http://code.sgo.to/hotels/123
> would look like with these constructs:
> 
> {
>   "@context": "http://schema.org",
>   "@type": "Hotel",
>   "@id": "http://localhost:5000/hotels/123",
>   "name": "Hilton",
>   "reservations": {
>     "@type": "ItemList",
>     "@id": "http://localhost:5000/hotels/123/reservations",
>     "operation": {
>       "@type": "SearchAction",
>       "actionStatus": "proposed",
>       "expects": [{
>           "@type": "SupportedClass",
>           "subClassOf": "LodgingReservation",
>           "requiredProperty": [
>              "http://schema.org/checkInDate",
>              "http://schema.org/checkOutDate",
>              "http://schema.org/numberOfAdults",
>              "http://schema.org/numberOfChildren"
>           ]
>       }],
>       "returns": "http://schema.org/ItemList",
>       "actionHandler": [
>         {
>           "@type": "HttpHandler",
>           "name": "Creates a new reservation for this hotel",
>           "httpMethod": "post",
>         }
>       ]
>     }
>   }
> }

Yeah, this looks much cleaner, but you cheated a bit by eliminating the actionHandler nesting :-) Furthermore, as soon as you need to add a single property (not just cardinality but also a *label* or a *description*) you would end up with exactly the same nesting. Have a look at this variation:

  {
    "@context": "http://schema.org",
    "@type": "Hotel",
    "@id": "http://localhost:5000/hotels/123",
    "name": "Hilton",
    "reservations": {
      "@type": "ItemList",
      "@id": "http://localhost:5000/hotels/123/reservations",
      "operations": {
        "@type": "BookAction",
        "name": "Creates a new reservation for this hotel",
        "method": "POST",
        "expects": [{
          "@type": "SupportedClass",
          "subClassOf": "LodgingReservation",
          "supportedProperty": [
             { "property": "checkInDate", "required": true },
             { "property": "checkOutDate", "required": true },
             { "property": "numberOfAdults", "required": true },
             { "property": "numberOfChildren", "required": true }
          ]
        }],
        "returns": "http://schema.org/ItemList"
      }
    }
  }

How do you find this version?

I removed the HttpHandler in the example. I know you probably need it to decide whether to invoke the operation directly and showing the user just the result or open a new browser window. That information could be expressed as an operation type if needed so, "@type": [ "BookAction", "WorkflowOperation" }. In lack of a better term I used WorkflowOperation to express that this specific operation is part of a larger workflow and that requires a new browser window to be opened so that the user can complete the remaining steps.


Cheers,
Markus


>> [1] https://developers.google.com/+/api/latest/moments/insert
>> [2] http://www.hydra-cg.com/spec/latest/schema.org/


--
Markus Lanthaler
@markuslanthaler

Received on Friday, 24 January 2014 16:48:36 UTC