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

On Tue, Jan 28, 2014 at 5:45 AM, Markus Lanthaler
<markus.lanthaler@gmx.net>wrote:

> On Monday, January 27, 2014 6:16 PM, Sam Goto wrote:
> > On Fri, Jan 24, 2014 at 8:47 AM, Markus Lanthaler wrote:
> > > On Friday, January 24, 2014 2:24 AM, Sam Goto wrote:
> > > > 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.
> >
> > The "crawler" part of this demo is here (super messy/hacky, sorry):
> >
> > https://github.com/samuelgoto/samuelgoto.github.io/tree/master/src
>
> Thanks
>
>
> > The "client/service/provider" part of the demo is currently in a private
> > repo, but I'd be happy to share if there is interest.
>
> That would be helpful as I could more easily look at all the
> representations you created without having to crawl the whole API.
>
>
> > > 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?
> >
> > I don't think so. There is some extra metadata that is needed to invoke
> > actions on android (e.g. the application package name. without it, any
> > application can filter to catch a specific url pattern) and windows (you
> > need things like ms-AppFamilyName, ms-AppId and ms-MinVersion to kick off
> > a native windows app).
> >
> > This also needs to work with iOS, so I don't think we can avoid action
> > handlers.
>
> Hmm... maybe that info could be moved into the description of the
> operation!? Similar to how the HTTP method is there.
>
>
> > On a related note, this is quite interesting too: http://appurl.org and
> > I'm really glad to see things like that popping up.
>
> Right, that's what I meant. I works by defining custom URL schemes and
> would thus integrate nicely. Your app defines a proprietary URL scheme it
> is able to handle and whenever a URL using that scheme is opened the app
> gets invoked. This is similar to skype: or tel: links on the Web today.
>
>
>
> >> > 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).
>

That's what I mean as being an added implementation complexity ("deal
breaker" is way too strong, apologies for the over-reaction). I certainly
understand the added value of having these vocabularies defined elsewhere
and dynamically fetched (with the proper caching/pre-computing), but that
adds up to the moving parts on a production system.

This is probably a tangent, but what's you plan to deal with external
vocabularies? Don't you need to pre-fetch/pre-compute the entire external
vocabulary before making sense of it? And if so, wouldn't you know that a "
http://mydomain.org/reviewBody" is a Property rather than a
SupportedProperty?


> 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.)
> >
> > Right. The extra hop might be a deal breaker for a few applications, like
> > gmail actions. I understand your point, I just think that we need to make
> > the simple case simple.
>
> Why do you consider it as a "deal breaker"? Is
>
>   "expects": {
>      "supportedProperties":  [ ... ]
>   }
>
> really that much more complex than
>
>   "expects": [ ... ]
>
>
> >> > 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).
> >
> > In this example, the user is "searching" for an available
> reservation/room
> > against the "reservations" list attached to a hotel. Once you find one
> > (which you do if you click on the SearchAction), you can ReserveAction an
> > individual LodgingReservation.
> >
> > So, you SearchAction against an ItemList (collection) of
> > LodingReservation. Separately, you
> > ReserveAction/ConfirmAction/CancelAction a LodgingReservation that is
> > available.
> >
> > Does that make sense?
>
> Hmm... yeah. The "Creates a new reservation for this hotel" description of
> SearchAction was confusing me. I think I wouldn't model it that way though.
> I find it a bit unnatural to *search* for a LodgingReservation I haven't
> made yet. I would rather use a AvailabilityEnquiryAction or something
> similar.
>
>
You'd be searching on the "available lodging reservations" collection. If
you look at the hotel-booking sites, they all use that same language (i.e.
you are not "searching" a reservation you "haven't made yet", you are
"searching for available ones").


>
> >>> 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?
> >
> > schema.org properties can take multiple types. It could potentially
> take a
> > SupportedProperty (in case you need to be more specific) as well as a
> > Property (in case you don't have any extra requirements).
>
> What I meant was that if you allow both, you can't use the short form as
> you
> wouldn't know what that URL stands for:
>
>   "requiredProperty": [
>     "name",
>     "dslkjwe"
>   ]
>
> Is "name" a Property or a SupportedProperty? What about "dslkjwe", i.e.,
> something your app hasn't seen yet?
>
>
>
> >> 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"
> >
> > Just sanity checking Markus: is this valid JSON-LD? i.e. is it legal to
> > say that the previous statement [1] corresponds to the following [2]
> > expanded statement?
> >
> > [1]
> >
> > "requiredProperty": [
> >   "http://schema.org/checkInDate",]
> >
> > [2]
> >
> > "requiredProperty": [
> >   {
> >     @type: Property,
> >     @id: "http://schema.org/checkInDate"
> >   }
> >  ]
>
> Yeah, if you type-coerce (http://www.w3.org/TR/json-ld/#type-coercion)
> "requiredProperty" in your context to be of type "@id" that works. You
> can't infer though that "http://schema.org/checkInDate" is of type
> "Property". At least not without setting rdfs:range of "requiredProperty"
> to "Property" (and you generally don't do that in Schema.org AFAIK). So it
> is just equivalent to
>
>   "requiredProperty": [
>     {
>       @id: "http://schema.org/checkInDate"
>     }
>    ]
>
>
> >>>           ]
> >>>       }],
> >>>       "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 :-)
> >>
> >> In our latest thinking (which I still need to put down on paper and
> >> publish), we think that the "expects" and "returns" constructs should go
> >> into the Action-level properties, because it may apply to multiple
> action
> >> handlers (example: if you have an android app as well as a web API, you
> >> don't want to repeat yourself what your API looks like).
>
> Definitely makes sense. Can't we get rid of actionHandler then at the same
> time by moving that information to the operation itself as already proposed
> above. In other words, an operation would not only be an HttpOperation but
> also, e.g., an AndroidOperation at the same time. The application which
> invokes it extracts the necessary information directly from the operation.
>
>   {
>     "@type": ["SearchAction", "HttpOperation", "AndroidOperation" ],
>     "httpMethod": "POST",
>     "androidIntent": ...  <-- or something similar, you get the idea
>   }
>
>
> > >> 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:
> >
> > Yep, in that case you'd want to use a SupportedProperty instead.
>
> Again, how do you distinguish between them?
>
>
The entire schema.org vocabulary is available in a machine-readable format,
so you can pre-fetch and pre-compute the entirety of the
properties/supportedproperties and know which is which (I understand how
that's a lot harder if you have an external and dynamic changing vocabulary
though). Right?


>
> >>   {
> >>     "@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?
> >
> > Does this version require any "automatic-expansion" that you mentioned
> > before? Or is this valid JSON-LD out of the box?
>
> It's valid JSON-LD out of the box. With "expansion" I was talking about
> how a JSON-LD processor interprets a JSON-LD document. Internally, it
> expands terms to URLs.
>
> See http://www.w3.org/TR/json-ld-api/#expansion
>
>
> >> 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.
> >
> > Handlers are not necessarily "workflow" specific. That is, they exist
> > because invoking actions in different platforms is complicated (e.g. this
> > is what it takes to invoke on android, and this is how you invoke on
> > windows).
>
> OK. What do you think about moving that information to the operation
> itself as suggested above? I haven't thought hard about it yet but I can't
> see any obvious disadvantages of doing so. Quite the contrary.
>
>
> Cheers,
> Markus
>
>
> --
> Markus Lanthaler
> @markuslanthaler
>
>

Received on Tuesday, 28 January 2014 15:49:51 UTC