RE: W3C standardization process

On Thursday, January 23, 2014 9:09 PM, James Langley wrote:
>> What kind of tooling would you need/like to have? What programming
language
>> are you using to implement your API/clients?
> 
> We're using Java for the API. We need to be able to treat the client
> response much like an XML DOM - the data would flow through a couple
> of layers in our architecture, and each layer should have the
> capability to modify the response.
> Siren4J provides a FluentBuilder API which allows us to construct a
> Siren payload easily enough, but doesn't seem to give the capability
> to modify it. There are other similar libraries for pure JSON
> handling, which again either assume you want to map to / from a POJO
> and a JSON representation, or allow you build a JSON object and
> convert it to a String. But we haven't yet found anything that would
> allow us to manipulate a JSON DOM like we could an XML DOM.

So you want to manipulate the JSON representation directly instead of
mapping it to domain POJOs, right? In my JSON-LD processor [1] I've
implemented a first version of a "node API" as I call it. That's very
similar to the FluentBuilder API you talk about. It's in PHP but I'm sure
you get the idea:

  // get the default graph from the JSON-LD request doc.
  $graph = $request->getGraph();

  $graph->getNode('http://example.com/node1')
    ->setType('http://example.com/vocab#SomeClass')
    ->setProperty('http://example.com/vocab#propertyA', 'A')
    ->removeProperty('http://example.com/vocab#propertyB');

  $serialized = JsonLD::toString($graph->toJsonLd());

Is that more or less what you are looking for? I'm not aware of a Java
implementation but there exists a Java JSON-LD processor [2] that implements
the difficult parts. You would just have to extend it with a "node API".

The biggest difference here is that JSON-LD deals with graphs whereas XML
DOMs represent trees but as soon as you introduce links you end up dealing
with graphs anyways.


> We haven't found any library that understands Hydra by default.

AFAIK there exists none at the moment. That being said, a Hydra description
is also just a JSON-LD graph. You just need to interpret the data properly.


> Hydra gives us some nice features from a testing perspective - the
> "returns" feature allows us to validate our API output automatically,
> and we can re-use the same validation to apply to client-supplied data
> for the "expects" side of things. It also seems that we can use the
> same Hydra context as both our test blueprint and our developer
> documentation, which is nice.

Right, that's one of the unique selling points of Hydra I would say. I
discussed that in detail in the "Model Your Application Domain, Not Your
JSON Structures" paper [3].



> It also seems that we can pass better semantics back to the clients
> (to support i18n, l10n, and accessibility issues) than Siren allows.

Yep, you get that more or less for free.


> (Because you don't seem to be able to assign a Siren Class to a Siren
> Property, only to an Entity.) I plan to raise that on the Siren Google
> Group later.

You mean defining the "range" of a property? I thought that's possible but
after re-checking the documentation I see it isn't. Apparently field types
are limited to the input types specified by HTML5 [4-5].


> Where Siren seems to have an advantage is where we want the API to
> change behaviour at runtime depending on the current server state,
> i.e. a Class should be POSTable sometimes but not alway;,

That's something we discussed in the context of authorization in the past,
see ISSUE-7 [6]. The general approach would be to either define a property
or a class that you include/exclude based on the resource state. Something
like

  {
    "@id": "just-an-entity",
    "@type": [ "BlogPost", "PublishedBlogPost" ],
    "comments": "just-an-entity/comments"
  }

In this case, the operations that are supported on all posts are associated
to the "BlogPost" class. The operations only applicable to published posts
are associated to the "PublishedBlogPost" class. Similarly, the "comments"
property is just included on posts that can be commented on.

I see that a lot of people run into this question, I've thus created
ISSUE-23 [7] so that we don't forget to explicitly mention it in the spec.


> or a POST may return one Class in some circumstances, and another
> Class at other times (and the two Classes are not both semantically
> subclasses of the same super Class). A static Hydra context doesn't
> allow this.

Do you need to document the circumstances under which each class is returned
or is it enough to know that you may get different responses? Depending on
whether you are willing to use other vocabularies or not, you might be able
to describe that using OWL. You could create a union class [8]:

  {
    "@context": {
      "owl": "http://www.w3.org/2002/07/owl#",
      "owl:unionOf": { "@type": "@id" }
    },
    "@id": "People",
    "@type": "owl:Class",
    "owl:unionOf": [ "Man", "Woman" ]
  } 

and use it in "returns". Depending on what we decide to do with multiple
values of "returns" and "expects" (are requests/responses instances of all
classes or just of at least one class; ISSUE-22 [9])


> (We have been thinking about serving different Hydra contexts at
> different times to get round this, but I'm not convinced taht's a
> god way to go.)

In most cases I agree it isn't a good way to address these issues. One
reasonable exception is if the operations depend purely on the
authentication of the user. In such a case I would say it makes sense to
dynamically serve different contexts and either serve them from different
URLs or include a Vary: Authorization header (or something similar) to avoid
caching problems.


> And because of the lack of an upfront API document, I suspect Siren
> client developers are more likely to code generic clients that can
> cope with any Siren response, whereas a Hydra client developer might
> code a client specific to our Context.

That's a valid concern. I deliberately left out a mechanism to describe
target URLs in a Hydra description to avoid that. So, in any case, a
developer would need to find the URL to POST to by inspecting responses he
gets. It's then only a very small step to retrieve and parse the Hydra
description dynamically as well. But you are right in principle. It should,
however, also be noted that you don't have to use a separate Hydra
description at all. You can also embed operations directly into responses as
Siren does. See example 6 in the spec [10]:

  {
    "@context": "http://www.w3.org/ns/hydra/context.jsonld",
    "@id": "/an-issue",
    "title": "Do not rely on upfront API document :-)",
    "description": "This issue can be deleted with an HTTP DELETE request",
    "operations": [
      {
        "@type": "DeleteResourceOperation",
        "method": "DELETE",
        "title": "Delete this issue"
      }
    ]
  }

The disadvantage of doing so is obviously an increased overhead. Typically,
in Web APIs responses don't vary much and thus it makes sense (IMO, anyway)
to move those descriptions into a separate document that can be cached for a
*long* time.

Btw. please don't conflate a JSON-LD context (which maps JSON elements to
URLs) with a Hydra description (which describes your service).


Cheers,
Markus


[1] https://github.com/lanthaler/JsonLD
[2] https://github.com/jsonld-java/jsonld-java
[3] http://m.lanthi.com/wsrest2013-paper
[4] https://github.com/kevinswiber/siren?source=c#type-1
[5] http://www.w3.org/TR/html5/forms.html#attr-input-type-keywords
[6] https://github.com/HydraCG/Specifications/issues/7
[7] https://github.com/HydraCG/Specifications/issues/23
[8] http://www.w3.org/TR/owl2-syntax/#Union_of_Class_Expressions
[9] https://github.com/HydraCG/Specifications/issues/22
[10]
http://www.hydra-cg.com/spec/latest/core/#adding-affordances-to-representati
ons


--
Markus Lanthaler
@markuslanthaler

Received on Friday, 24 January 2014 13:30:36 UTC