Re: Express "go to specific page" for a collection

Hi Philipp

I think you should use plain text :)

Also sorry I will be a little bit off topic for part of my reply.

On Thu, Jul 10, 2014 at 8:43 AM, Philipp Zins <pipo@senaeh.de> wrote:
> Hi Markus,
>
>> That's great. AFAIK, we didn't have (m)any frontend developers in the
>> group till now. So your input will be very helpful to improve Hydra.
>
>
> I'm happy to give input. I think my view on a Hypermedia API is quite
> influenced from being a frontend developer as you will see in the following
> answer.
>
>> Could you tell us why you currently favor JSON Hyper-Schema and briefly
>> explain how you use it on the frontend? For example, do you use it to
>> automatically generate forms?
>
>
> With my "current" knowledge about HATEOAS I have the following philosophy:
> HTML is the best hypermedia format I know and our JSON hypermedia format
> should use the same principles.
>

I've just discussed this with a colleague yesterday and my conclusion
is that HTML and Web API hypermedia differ in a fundamental yet subtle
way. HTML is a markup of the view while any JSON/XML/RDF/whatever that
client and server communicate with is tha data. And so the hypermedia
is move to another layer of applications.

>
> That said a user who browsers the web consumes the HTML document. A normal
> user doesn't look into HTTP headers. Likewise a client should gather all the
> data it needs from the JSON payload. There is no need for the client to
> consume HTTP headers - they're only really needed for the browser (e.g. for
> caching information).
> A user interacts with the HTML document via links (anchors or buttons). They
> know what they do, because they are labeled (e.g. "Buy now", "Click here to
> login", "Close this window"). A good JSON hypermedia format has a similar
> way to share vocabulary between server and client. Most formats seem to rely
> on "rel" and Link Types for this (e.g. "next", "prev", "index", "help",
> "edit"). I don't know if this is sufficient and I think this could be one of
> the major advantages of JSON-LD (- using schema.org for common vocabulary
> and Hydra for API-specific vocabulary). At least if I understand JSON-LD
> correctly.
> Links in HTML documents are placed relative to their content (e.g. place a
> "share button" under every article in a blog - opposite to gathering "all"
> links at a central place). The JSON hypermedia format should do the same.
> Every resource has its own "links". (See the following example.)
>

This is precisely what Hydra does. SIREN for example does what you
mention. The response is split into a semantically different
representation, where the class, properties, links and actions are
completely different, hence the contract is totally different that if
HAL was used. Or no hypermedia was used at all:

{
  "class": [ "order" ],
  "properties": { "orderNumber": 42, "itemCount": 3, "status": "pending" },
  "entities": [ { ... }, { ... }],
  "actions": [ { "name": "add-item", "method": "POST" } ],
  "links": [ { "rel": [ "self" ], "href": "http://api.x.io/orders/42" }, ...]
}

I don't really understand the entities property, but that's the point.
Wihtout SIREN the response would probably be much simpler:

{
  "class": "order",
  "orderNumber": 42,
  "itemCount": 3,
  "status": "pending"
}

This is because (every?) other hypermedia format defines not only the
semantics but also the syntax. HAL is a bit better in this regard, but
it introduces the "_embedded" property for example. This is very much
like the media type nonsense. With Linked Data (and Semantic Web in
general) you always speak about resources in an abstract way. It's the
semantics that matter. JSON-LD, Turtle, RDF/XML are just syntax. Thus
in Hydra you won't see mime types. Properties and operations are
defined in terms of classes, ie. that an operation returns (an
instance of) a specific class. Or requires an instance as input.

And so because Linked Data operates on a model, Hydra extends existing
data rather than turn in upside-down. You can extend individual
instances or their classes, because the format makes it possible. And
so, yes, each instance can have its own link and operations.
Furthermore if any Web API switched from Hydra to some other
RDF-compatible hypermedia description the actual data will be
unchanged. And so any client that ignores hypermedia would never
notice the difference. With a move from HAL to SIREN all clients
break, because the messages change completely.

>
> A form isn't much different from a common link: it just gathers some
> additional data and than you can follow "the link of the form" via a submit
> button. You can even specify the HTTP method which should be used. A JSON
> hypermedia format should include the same information: what data is needed
> to follow the link and what HTTP method should be used?
>

I actually think that the term "hypermedia format" is not correct in
terms of Hydra. There already is a format and its called RDF. In
itself it is not enough for self-descriptive representations. However
Hydra is not a new format. Nor does it change RDF in any way. It is
merely an extension, which allows augmenting existing data with
description of hypermedia controls.

>
> With these requirements in mind that is how we use JSON Hyper-Schema (basic
> example):
>
> // GET https://api.example.com/users
> {
>   // Every "_schema" of a resource is a valid JSON Hyper-Schema.
>   // Every resource has its own "_schema": Here we have a users collection
> as one resource
>   // containing two users which each are a resource, too. If you want these
> users could also contain
>   // nested resources like friends, hobbies, etc.
>   "_schema": {
>     // We mostly need the "links" field from JSON Hyper-Schema, but you
> could really use all of JSON
>     // Hyper-Schemas features (e.g. create a schema definition for the users
> collection itself).
>     "links": [
>       {
>         "rel": "self",
>         "href": "https://api.example.com/users",
>         "method": "GET"  // GET is default as in the browser. You don't to
> specify it.
>       },
>       {
>         "rel": "create",
>         "href": "https://api.example.com/users",
>         "method": "POST",
>         // This schema definition tells us that we need a "name" to create a
> new user and can
>         // optionally pass a "description".
>         // A schema definition like this refers to the request body for
> POST, PUT and PATCH
>         // (if you need PATCH) and to the query string for GET and DELETE.
>         // (This is similar to UBER.)
>         "schema": {
>           "type": "object",
>           "properties": {
>             "name": {
>               "type": "string"
>             },
>             "description": {
>               "type": "string"
>             }
>           },
>           "required": [ "name" ]
>         }
>       }
>     ]
>   },
>   // Some arbitrary data on the collection resource.
>   "total": 2,
>   "users": [
>     // Every item of "users" is also a resource, so they have "_schema"
> definitions.
>     {
>       "_schema": {
>         "links": [
>           {
>             "rel": "self",
>             "href": "https://api.example.com/users/xxx-123"
>           }
>         ]
>       },
>       // Some arbitrary data on this user resource.
>       "id": "xxx-123",
>       "name": "John",
>       "description": null
>     },
>     // Every item of "users" is also a resource, so they have "_schema"
> definitions.
>     {
>       "_schema": {
>         "links": [
>           {
>             "rel": "self",
>             "href": "https://api.example.com/users/abc-124"
>           },
>           // I can dynamically add or remove "link" objects. We don't need
> to use the same
>           // for every user. Maybe I can remove this one, because it is an
> intern and not an
>           // admin.
>           // We rarely need URI templates, as we include an absolute base
> ("https://api.example.com/users/abc-124")
>           // and define query params with "schema", if we need them.
>           {
>             "rel": "remove",
>             "href": "https://api.example.com/users/abc-124",
>             "method": "DELETE"
>           }
>         ]
>       },
>       // Some arbitrary data on this user resource.
>       "id": "abc-124",
>       "name": "Mica",
>       "description": "Just an intern..."
>     }
>   ]
> }
>

This is interesting. I haven't seen the JSON Hyper-Schema before and
it doesn't have the shortcomings I explained above in that the "core
representation" stays intact when adding hypermedia definition.
However the first sentence reads "JSON Schema is a JSON based format
for defining the structure of JSON data", and so it is still a new
format, albeit JSON-based.

All in all I see a lot of similarities between JSON Hyper-Schema and
Hydra. You could almost envision a tool to covert the former into the
latter.

>
> Yes, generating (or evaluating) forms is one of the benefits of this
> approach which we use. E.g. in a "create new user form" we could
> automatically set the "required" attribute on the input element for the user
> name.
>

Hydra gives you all that functionality, doesn't it?

>
>> What are those benefits? Apart from the "go to specific page" feature,
>> what else is currently missing in Hydra in your opinion?
>
>
> I can't say what is missing in Hydra yet as I hadn't enough time to look
> deeply into Hydra. A "go to specific page" feature would be very easy with
> JSON Hyper-Schema: just add a new "link" object on the collection which has
> a schema definition that requires a "page" param with an int value. (The
> server could automatically include a "min" and "max" page, too. Very handy.)
>

Unlike next/prev page, which Hydra defines out of the box, there
probably won't be a goToSpecificPage property, because it requires the
use of a IriTemplate. However all the building blocks are there.

Markus, please correct me here. Also I think that the vocabulary
documentation page is a bit lacking in this regard. I would add a
complete example of how a IriTemplate fits into a resource
representation.

>
> I hope you have a picture of what we want to achieve now :)
>
> Btw, I'm coming from Leipzig. I saw that one person in the Hydra group is
> associated with the university of Leipzig. What a coincidence! We're
> literally neighbors :)
>
> Cheers,
> Pipo
>
>
> 2014-07-08 13:17 GMT+02:00 Markus Lanthaler <markus.lanthaler@gmx.net>:
>
>> Hi Pipo,
>>
>> On Tuesday, July 08, 2014 11:42 AM, Philipp Zins wrote:
>> > > Does your use case really require it?
>> >
>> > I would say, yes. If you compare some GUI pagination patterns (see
>> > https://gist.github.com/mislav/622561) you can see that roughly 50%
>> > allow the user to jump to an arbitrary page.
>>
>> When it comes to GUIs it is indeed an often used pattern. The question
>> however is, if this really needs to be supported by the API directly as
>> well. It depends entirely on the application I would say. How often does a
>> user jump from page 1 to page 213 and then back to page 49? If it doesn't
>> happen often (and it isn't needed to support certain use cases), it's better
>> to avoid supporting it directly IMO. The client can prefetch the next x
>> pages and then render direct links just to those pages (1 2 3 4 .... last
>> page).
>>
>> It all depends on the use case. I would thus like to have a concrete
>> scenario that really requires it, i.e., that can't be solved otherwise. Do
>> you have one?
>>
>>
>> > What do you think about Jindřich comment with the anonymous anonymous
>> > property?
>>
>> Jindřich said:
>>
>>   Instead of using hydra:freetextQuery for hydra:property mapping in
>>   the hydra:IriTemplateMapping, I think you can use an anonymous
>>   property with rdfs:range defined to be xsd:positiveInteger:
>>
>>   "property" : {
>>     "rdfs:range" : "xsd:positiveInteger"
>>   }
>>
>>   Although I'm not sure if using anonymous properties in such case is
>>   an accepted practice in Hydra.
>>
>> I wouldn't use an anonymous property in this case as it is crucial for the
>> client to understand what the property is about. Just telling the client
>> that the value should be a positive integer isn't enough IMO. The client
>> needs to know that this represents the page number. It also needs to know if
>> the first page is 0 or 1 or if the page number is actually an offset (11
>> instead of 2 for page 2 if each page has 10 items).
>>
>>
>> > Some background: I'm mainly a frontend developer switching to the
>> > backend here and there. As we try to move more development processes
>> > to the client (for better iteration speeds, dynamic and fluid GUIs,
>> > etc.) we need a good interface between server and client. We really
>>
>> That's great. AFAIK, we didn't have (m)any frontend developers in the
>> group till now. So your input will be very helpful to improve Hydra.
>>
>>
>> > like the idea of Hypermedia APIs (instead of RPC-ish "REST" APIs) and
>> > I try to evaluate different solutions. We currently favor JSON Hyper-
>> > Schema directly embedded in our resources,
>>
>> Could you tell us why you currently favor JSON Hyper-Schema and briefly
>> explain how you use it on the frontend? For example, do you use it to
>> automatically generate forms?
>>
>>
>> > but I would like to explore
>> > if we can move to Hydra/JSON-LD completely in the next turn as it
>> > seems to be a more widely used standard and because JSON-LD is
>> > supported by all major search engines. But I don't want to loose the
>> > benefits of JSON Hyper-Schema.
>>
>> What are those benefits? Apart from the "go to specific page" feature,
>> what else is currently missing in Hydra in your opinion?
>>
>>
>> Cheers,
>> Markus
>>
>>
>> --
>> Markus Lanthaler
>> @markuslanthaler
>>
>>
>

Received on Thursday, 10 July 2014 07:47:07 UTC