- From: Markus Lanthaler <markus.lanthaler@gmx.net>
- Date: Mon, 13 Oct 2014 17:25:18 +0200
- To: <public-hydra@w3.org>
Hi Dietrich, Since most questions have already been answered, I'm focusing on those that haven't (or need more explanation) in this mail. On 7 Okt 2014 at 09:03, Dietrich Schulten wrote: > The meat of the event-api is at > http://www.markus-lanthaler.com/hydra/event-api/vocab. Observation: the > vocab is quite lengthy for a simple use case. 241 LOC, much of it seems > repetitive. I haven't optimized this at all yet. That being said, I don't think this will cause any performance problems in practice. Typically, the overhead due to this manifests itself only in the very first request. > We are talking about a pretty standard situation: you can POST, PUT > and DELETE to the /events resource. If you POST or PUT, your request > should contain an object that has attributes as defined by > http://schema.org/Event. Only some of them are required, most are not > supported. So what's standard about this? :-) I know of no standard that defines this. It is certainly a common pattern but not more. > My general feeling is: it should not be necessary to maintain such a > large description. Somehow we must leverage convention over > configuration and the existing vocabs in such a way that I only need > to define things I cannot take for granted. So, in your opinion, what things could we take for granted? > And we must be more DRY. Yes, definitely. Optimizing this is on my to do list. > I want to keep my context short so I can embed it. With Javascript > clients in mind, I'd rather have everything in the resource that is > needed to work with it. The Hydra ApiDocumentation we are talking about here and a JSON-LD context are two entirely different things. The former describes the service interface, the latter defines the mapping from terms (think JSON property names etc.) to IRIs. > First of all, http://schema.org/event appears on Place, Organization > and a number of Actions. In RDF, are we free to use schema:event on an > EntryPoint? Can I state > > "schema:event rdfs:domain hydra:EntryPoint" > > somewhere in my context to allow this usage? And do I have to, don't I > say that already by using schema:event on a hydra:EntryPoint? In the > json world no "static typing" exists that would prevent me from adding > any attribute. In RDF, basically everything is allowed unless it is explicitly forbidden. You also need to keep in mind that RDF is typically defined in terms of entailments and not constraints. In this case here that would mean that schema:event rdfs:domain hydra:EntryPoint doesn't say that the event property can *only* be used on EntryPoints but that all resources that the event property is used on *are* in fact EntryPoints. So, with the above statement, the following snippet </resource> rdf:type ex:JustAResource ; schema:event ... isn't invalid. It is completely fine.. but you need to keep in mind that RDFS-aware clients would interpret this as </resource> rdf:type ex:JustAResource ; rdf:type hydra:EntryPoint; <--- this is inferred schema:event ... This is probably the most confusing aspect of RDF (and RDFSchema, which doesn't define "schemas" in the traditional sense). > Second: Assuming that we are allowed to use http://schema.org/event: > Values of schema:event are expected to be of type Event, not of type @id. This is a JSON-LD convention. Type-coercing a property to @id allows you to use string values instead of @id-objects: { "@context": { "event": { "@id": "http://schema.org/event", "@type": "@id" } }, ... "event": "http://example.com/my-event" } is equivalent to { "@context": { "event": "http://schema.org/event" }, ... "event": { "@id": "http://example.com/my-event" } } but looks nicer if you don't have to attach other properties to /my-event. If you wouldn't type-coerce "event" to @id in the first example, the URL wouldn't be interpreted as a URL but just as a string. In other words, it would be the same as { "@context": { "event": "http://schema.org/event" }, ... "event": { "@value": "http://example.com/my-event" } } > It would be easy to program clients so that they understand the > difference and transparently resolve links for data. But does RDF > allow that? Is it correct to use a link to events instead of embedding > the events themselves? If not, can Hydra introduce such a convention? Yes, it is effectively the same. The only difference is that you need more HTTP roundtrips to retrieve the data. > Or can I at least redefine > > "schema:event rdfs:range jsonld:@id" > > somewhere in my @context? No > On to the EventCollection. My wishful-thinking EventCollection: > > { > "@context": { > "@vocab": "http://schema.org", > "hydra": "http://www.w3.org/ns/hydra/core#" > }, > "@id": "http://www.markus-lanthaler.com/hydra/event-api/events/", > "@type": "hydra:Collection", > "hydra:member": [ > { > "@id": "http://www.markus-lanthaler.com/hydra/event-api/events/1", > "@type" : "hydra:Link" The resource /events/1 isn't a hydra:Link but a schema.org/Event or hydra:Resource as others pointed out already. > }, > { > "@id": "http://www.markus-lanthaler.com/hydra/event-api/events/2", > "@type" : "hydra:Link" > } > ], > "hydra:operation": [ > { > "method": "hydra:CreateResourceOperation", > "hydra:supportedProperty" : [ You do realize that by doing it this way you reduce re-usability compared to how we currently do it in Hydra, right? Currently, you would just have to specify "hydra:expects": "Event" and bind the supported properties to that class. But what surprises me more is > "name", > "description", > "startDate", > "endDate", > { > "property": "performer", > "required" : false, > "hydra:supportedProperty" : [ > "name" > ] This nesting of supported properties. This would effectively say that a property supports another property. I think what you actually wanna say is that the value (range) of that property supports this other property, right? > } > ] > } > ] > } > > I assumed that we could have several conventions here. > > 1. It is usually not necessary to know the type of the collection > members in order to create them, since the properties we send are by > definition in the domain of a Thing, e.g. Event. Right, but in most cases it makes the server's implementation much much simpler since it is easier for the server to find the right resource in the graph that the client sends in the request. > Therefore I simply used hydra:Collection. This hasn't much to do with the type of the collection's members. > Maybe Collection could have a "hydra:of" Property so that one could say > "@type": { > "@id": "hydra:Collection", > "hydra:of" : "Event" > } > rather than defining a custom class. > But right now I do not see the need for a hydra:of or for typed > collections. Well, I guess there *is* a reason why you introduced the > EventCollection :) Could you explain? I introduced EventCollection because I needed a specialization of the generic Collection class to associate an operation to it that then automatically applies to all its instances. Assume we also have a collection for performers. In that case I can't associate the "create event operation" to hydra:Collection because then it would also apply to performer collections. Obviously, if you define operations inline instead of defining them in the ApiDocumentation at the class level you don't need to introduce a specialized class. I explained this in my talk at APIconUK: http://youtu.be/fJCtaNRxg9M?t=21m30s slides: http://slidesha.re/1tB6TFC > 2. The usual case is that an operation is supported when the resource > comes with the appropriate affordance. Mostly it is not something that > is always supported, since that does not depend on the Class, but on > the usage context. E.g. posting a new Event is probably not supported > if you do not have sufficient rights to do so. The server simply does > not include it if it is not supported. I can hardly imagine cases > where a state-changing operation is *always* supported on a resource. > Hence I put the operation into the resource, not in the documentation. That's a decision you have to make. Nevertheless, you can use classes as "markers" to enable/disable functionality at runtime (kind of feature flags). That way, instead of having to include the complete definition of an operation, you simply add or remove a class from that specific instance depending on the user's permissions. > 3. It is usually only necessary to list the names of supported > properties for an operation, so instead of saying "property": "xxx" > many times I just listed the property names. Yeah, we track this as part of ISSUE-37 [1]. > 4. There is no need to describe the meaning of status codes in the > resource. I am strongly against overriding the meaning of existing or > defining custom HTTP status codes anyway :) The body of an error We do not want to override it but add some more details. > response is the place to give hints how to resolve a problem, and it > should probably follow > http://tools.ietf.org/html/draft-ietf-appsawg-http-problem. Could It's quite closely aligned already AFAICT. > hydra:Error be redefined in such a way that a json-ld client accepting > ld+json could by convention get the below error response (with the > standard properties type, title, status, detail, instance and two > extension properties)? What would we need to redefine to achieve that? Please also have a look at ISSUE-27 [2] and ISSUE-39 [3]. > > HTTP/1.1 403 Forbidden > Content-Type: application/problem+json You either need to change the content type to application/ld+json or add an HTTP Link header [4] to make it clear to clients that this can be interpreted as JSON-LD. > Content-Language: en > > { > "@context": > { > "@vocab" : "http://www.w3.org/ns/hydra/core#", > "balance" : "http://bank.example.com#balance", > "accounts" : "http://bank.example.com#accounts" > } > "@type": "Error", > "type": "http://example.com/probs/out-of-credit", > "title": "You do not have enough credit.", > "status": 403, > "detail": "Your current balance is 30, but that costs 50.", > "instance": "http://example.net/account/12345/msgs/abc", > "balance": 30, > "accounts": ["http://example.net/account/12345", > "http://example.net/account/67890"] > } > > - ------------------------ > > Up next, Event: > > { > "@context": { > "@vocab": "http://schema.org", > "hydra": "http://www.w3.org/ns/hydra/core#" > }, > "@id": "http://www.markus-lanthaler.com/hydra/event-api/events/1", > "@type": "Event", > "name": "Walk off the Earth - REVO tour", > "description": "Live in concert", > "startDate": "2014-06-14T20:00:00Z", > "endDate": "2004-06-14T23:34:30Z" > "hydra:operation": [ > {"hydra:method": "DELETE"}, > { > "hydra:method": "PUT", > "hydra:supportedProperty" : [ > "name", > "description", > "startDate", > "endDate", > { > "property": "performer", > "required" : false, > "hydra:supportedProperty" : [ > "name" > ] > } > ] > } > ] > } > Since I have sufficient rights, I can delete and replace the event. > When I replace an Event, I must send the same data as for a creation. OK, and how should a machine figure that out? > Clearly our operations overlap with http://schema.org/Action. > I tried to add a schema:ReviewAction onto the Event above, but I ran > into several problems. That is worth a different discussion, however. > > - ------------------------ > > Conclusion: > > In my opinion, this should be all I need to say for the simple CRUD use > case under discussion. But I guess there are some pitfalls I fell into. > > I guess the event-api as it is today tries to solve a slightly > different problem, maybe to keep the json resource as terse as possible. The goal of that demo API is to show that a JSON-LD + Hydra powered Web API can look almost exactly the same as a traditional JSON-based Web API but nevertheless have the advantage of self-describing messages (aka well-defined meaning) and support for hypermedia (links and operations). It also acts as a show case of how to upgrade an existing JSON-based API to se JSON-LD + Hydra. > I see that quite relaxed, my idea is, if you request application/json instead > of ld+json, then the server returns a response as terse as can be. But that changes the interpretation completely. In other words, the responses lose *all* their meaning. Thanks for taking the time to write all of this down, Markus [1] https://github.com/HydraCG/Specifications/issues/37 [2] https://github.com/HydraCG/Specifications/issues/27 [3] https://github.com/HydraCG/Specifications/issues/39 [4] http://www.w3.org/TR/json-ld/#interpreting-json-as-json-ld -- Markus Lanthaler @markuslanthaler
Received on Monday, 13 October 2014 15:25:51 UTC