- From: Sam Goto <goto@google.com>
- Date: Tue, 28 Jan 2014 07:49:22 -0800
- To: Markus Lanthaler <markus.lanthaler@gmx.net>
- Cc: W3C Web Schemas Task Force <public-vocabs@w3.org>, public-hydra@w3.org
- Message-ID: <CAMtUnc648LJUcMfwLpMB=_SUnqASzf9BcZSNzGnsrOwUiOmu3A@mail.gmail.com>
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