Re: My opinion about hydra vocabulary

Thanks the feedback!

Huh where to start. :-)

HAL+JSON is not very suitable for the kind of services we are talking about
in the context of Hydra. HAL more or less just provides an envelope for JSON
representations to add a couple of hyperlinks. You can achieve exactly the
same by using HTTP Link headers and keep your ordinary JSON. With Hydra and
JSON-LD in contrast, all properties are unambiguously identified by URLs,
not just links.

 

By HAL+JSON with link relations it is a bit trickier to describe type and
linked data connections, but it's not impossible:

    {
        _embedded: {
            name: {
                value: "László",
                _links: {
                    type: {href: "http://my.api/docs/User/name"},
                    profile: {href: "http://schema.org/name"}
                }
            }
        }
    }

or with external file:

   {
     "name": "László",
     _links: {
        type: {href: "http://my.api/docs/User"}
     }
   }
   
   GET http://my.api/docs/User
   {
        _embedded: {
            name: {
                _links: {
                    type: {href: "http://my.api/docs/User/name"}, //or just
simply an url to String type
                    profile: {href: "http://schema.org/name"}
                }
            }
        }
   }

   

With CURIE-s you can use shorter links...

The "knows" here is the link relation type. As the name suggests, it defines
the type of relationship these two resources stand to each other. What
"Resource Method" does that link call? I don't know. Now I think you were
thinking more of something like

  /an-issue --[ comments ]--> /comments

 

There are standardized link relations on the iana page. For example by edit
you can always use PUT, by self you can use always GET, by service you can
use always GET, and your client will be hardcoded to interpret that link as
the entry point to a REST service. So by link relations you have to teach
your client every link relation you use in your REST service. For example by
comments, you can use a collection relation and maybe your custom "comments"
relation too. After that the comments page uses an item relation to every
single comment, etc... So the link relation depends on the resource and on
the context in where the resource is... For example a single comment has an
item relation in the context of the comments collection, and has  a self
relation in the context of itself. Btw this is the logic of the HAL+JSON
documents. JSON-LD has different logic. :-)

 

  {
    "@context": "http://www.w3.org/ns/hydra/context.jsonld",
    "@id": "#comments",
    "@type": "Link",
    "title": "Comments",
    "supportedOperations": [
      {
        "@type": "CreateResourceOperation",
        "title": "Creates a new comment",
        "method": "POST",
        "expects": "#Comment",
        "returns": "#Comment",
      }
    ]
  }

With HAL+JSON and link relations your JSON-LD document can be described as
something like this:

  {
    "title": "Comments",
    _links: {
        create: {
            href: "/issue/24/comments",
            "title": "Creates a new comment",
            "expects": {href: "http://my.api/docs/issue/comments/comment"}
        },
        self: {href: "/issue/24/comments"},
        type: {href: "http://my.api/docs/issue/comments"}
    }
  }

 

It does not use returns, because the HAL+JSON always describes itself, so if
it uses the create link, it will POST the input fields, and the response
will contain the type of the "returns" part. The field descriptions can come
from the documentation of the "expects" part, or can be given by each link,
for example:

  {
    "title": "Comments",
    _links: {
        create: {
            href: "/issue/24/comments",
            "title": "Creates a new comment",
            "fields": {
                title: {type: "string", min: 0, max: 127},
                description: {type: "markdown", min: 10, max: 2000}
            }
        },
        self: {href: "/issue/24/comments"},
        type: {href: "http://my.api/docs/issue/comments"}
    }
  }

 

Currently there are not a full standard by link relations and almost nothing
about how should we describe input fields by complex links.

These are just examples of usage. I am currently working on an application
which uses these examples, and after that with many refactoring maybe I will
be able to describe documentation as well...

Maybe it is possible to merge our approaches, maybe not, but I am sure we
can learn from each other. At least I learned how to describe a linked data
connection in HAL+JSON from your JSON-LD examples...

You mean instead of using IRI templates you would move the parameters into
the description of operations? How would you describe a URL template like
this in that case:

  /users-{lastname]-{id}/

 

Nope. I meant, that if I am right you describe the queryString part with
your IRI templates, about something like this:

new IRITemplate({
    template: "/users/{user-id}/comments?sort={sort-type}",
    mappings: [
        new IriTemplateMapping({
            variable: "user-id",
            property: "docs/user/id",
            required: true
        }),
        new IriTemplateMapping({
            variable: "sort-type",
            property: "docs/users/user/comments/params/sort-type",
            required: false
        })
    ]
})

 

I would rather separate the URL.path from the URL.queryString, and use the
path to indentify resources and the queryString to describe resource
modifiers, resource filters. I am currently working on how to describe these
variables, I have currently just a vague thoughts about this question, an
ad-hoc example:

CommentsMeta = {
    path: "/users/{User.id}/comments",
    properties: {
        "{Comment.id}": "{Comment}"
    },
    methods: {
        GET: {
            features: {
                sortable: [
                    {
                        variable: "sort",
                        source: {
                            "{Comment.id}": {
                                title: {
                                    comparator: "string"
                                },
                                creationTime: {
                                    comparator: "dateTime"
                                }
                            }
                        },
                        required: true
                    }
                ]
            }
        }
    }
}

and by link url creation:

new Url({
    path: "/users/24/comments",
    features: {
        sortable: {
            title: true
        }
    }
}) 

 

So overall, I am still working on a stable rest documentation format, if I
am done, I'll let you know...




 

 

2014-01-24 Markus Lanthaler <markus.lanthaler@gmx.net>

Hi László,

First of all, thanks again for taking the time to write this up. Much
appreciated. I'll insert my answers/comments/questions inline below.


On Friday, January 24, 2014 1:45 PM, László Lajos Jánszky wrote:
> Hi everybody!
>
> My name is László (means Ladislav) Jánszky and I'm glad to be part of
> this group. I have my own opinion about Hydra what I'll share with you
> in the current post. I propose you to do the same, because everybody
> has a different viewpoint, everybody can add his/her knowledge and
> experience to our model of REST APIs.
>
> First of all I want to thank you Markus for your work! It is very

Cheers :-)



> important to have a common model for REST APIs because without a
> common vocabulary we cannot describe the interface of RESTful
> applications, and without descriptions we cannot make tools to ease
> the development of these applications by generating at least the API
> part of them. Your work is a very good beginning, however I think it
> is not perfect, and I have recommendations which can maybe help you to
> improve it.

Thanks for sharing them.



> Recommendations about the documentation
>
> Illustration
>
> The illustration contains an arrow which is maybe an error its source
> is the Operation, its target is the Resource.operations and its type
> is rdfs:subClassOf. I don't think that the Operation class is a
> subClass of Resource.operations which is a property. Maybe I am wrong
> with this...

Yeah, you misread the diagram. The target is just "Resource" not
"Resource/operations". I always point to properties from the side, never
from the bottom. You can see similar arrows pointing to the bottom of the
Operation class.  But you are right, that's confusing just as


> The 2 type of arrows on the illustration are too similar.

I've filed ISSUE-24 [1] to keep track of this. Thanks for the feedback.
That's something I have been concerned with myself (thus the issue marker in
the spec).



> I think you
> should have created an UML class diagram instead of your custom
> diagram type. It would be easy understandable for everyone. There are
> great tools to create such diagrams...

>From my experience, UML diagrams are not that well understood as typically
claimed. Furthermore, they look quite complex if you try to use them
correctly. There exists a UML profile for RDFS/OWL in the official OMG ODM
standard but I don't find their graphical representation very compelling.
However I haven't managed to find or come up with a better representation
yet.


> Documentation and examples
>
> I don't think you should restrict the examples to JSON-LD only.. By

> RESTful applications, you can use many different hypermedia types,
> which can be used to describe the Hydra classes in a slightly
> different way than you do with your media type. For example it can be

Yeah, people asked specifically for Turtle in the past (see ISSUE-18 [2])
and Ruben "volunteered" to translate the examples.



> done with the HAL+JSON media type and the self, type and profile link
> relations too...

HAL+JSON is not very suitable for the kind of services we are talking about
in the context of Hydra. HAL more or less just provides an envelope for JSON
representations to add a couple of hyperlinks. You can achieve exactly the
same by using HTTP Link headers and keep your ordinary JSON. With Hydra and
JSON-LD in contrast, all properties are unambiguously identified by URLs,
not just links. So instead of

   {
     "name": "László"
   }

you have something like

   {
     "@context": { "@vocab": "http://schema.org/" },
     "name": "László"
   }

which internally transforms your data to

   {
     "http://schema.org/name": "László"
   }

If you don't know what "name" means, you just go and look it up at
"http://schema.org/name". That applies to basically everything in such
representations.



> The Hydra vocabulary is a namespace with classes and interfaces, and
> it should be documented as usually classes and interfaces by any

> namespace or framework are [http://pages.github.com/].
<http://pages.github.com/%5d.> ..

What advantages would using GitHub pages instead of a HTML page hosted on a
domain we own have?



> Recommendations about classes in the Hydra vocabulary
>
> I thought a lot about how to model REST APIs. From the current Hydra
> vocab I learned how to bind the resource classes and their properties
> with to the linked data. I think the idea behind this part of the
> vocabulary is perfect. Yes we need Resource, Property and Link classes
> to do this, and we have to bind these classes with their instances and
> with the linked data. I don't think this part can be done better.

Great :-)



> I think the other part of the vocab which describes links, operations,
> status codes, search queries is not so good. I can offer a better
> concept I think.
>
> The REST (representation state transfer) architectural style means
> that we should synchronize the application state with the resource
> state due to sending representations of each state to the maintainer
> of the other state. For example by GET requests we send the
> representation of the resource state to the client in the body of the
> HTTP response in order to change the application state. By PUT and
> POST requests we send the representation of the application state to
> the web service in the body of the HTTP request in order to change the
> resource state.
>
> Each of these Transfers are part of a bigger thing which is called
> Application State Transition. Application State Transition consist of
> many parts:
>
> • Application State Transition

>   o Current Application State - this is the current viewpoint of the

>     client. A part of this is sent with the Transfer, another part of
>     this is used with the Hypermedia to build the next Application
>     State.

>   o Link relation - this helps to put the current Transition in the

>     proper Context. This part of the Transition is used on the client
>     side only. For example an edit relation with 200 status code means
>     that the content of the input fields are now part of the resource
>     state, so they can be used by any representation of the targeted
>     Resource. A delete relation (haven't found a link relation for this
>     on the IANA site) with 204 status code means that the Resource is
>     no longer part of the Resource State, so any representation of it
>     can be deleted from the Application State.

>   o Representation State Transfer - this synchronizes the application

>     state and the resource state. By REST the server every time
>     performs and Abstract Application State Transition, which result is
>     sent back to the client in a Hypermedia format. So this Hypermedia
>     contains the description of the next Application State, that's why
>     they call Hypermedia the Engine of the Application State.

OK, overall I agree with this description even though I would use slightly
different terminology and avoid talking about synchronization.

>     • Http Request

>        • Http method - this is the identifier of the Method called
>          on the Resource instance.
>        • URL.path - this is the identifier of the targeted Resource
>          instance.
>        • URL.query, HTTP headers & cookies - these contain the

The URL query parameters are part of the URL and thus identifying the target
resource.



>          Context of the Abstract Transition. The Context is the
>          unique viewpoint of the client, it can contain
>          authorization headers, pagination details, sorting details,
>          search queries, etc... The Context can modify the running
>          of the Resource Method and so the result of the Abstract
>          Transition, and so the result of the Transition.

OK.. it's additional information, aka metadata, about an HTTP message.


>        • body - by write requests this contains the Representation

>          of the current Application State, which is the
>          Representation of the relevant part of the next Resource
>          State (by valid requests only ofc).
>     • Http Response
>       • Status - this is the status of the Abstract Application
>         State Transition. It contains code, title and description.
>         This part is well described by the vocabulary.
>       • HTTP headers & cookies - they can contain the preferred
>         settings of the user. For example the name of the client
>         skin, the default item count on a page, etc...
>       • body - by read and (sometimes) write requests this contains
>         the Representation of the current Resource State, which is
>         the  Representation of the relevant part of the next
>         Application State.
>
> Okay so what do we have here? Which part of this desciption interferes
> with the current Hydra vocabulary?
>
> • Links and Operations are not so different, I think the can be the
>   same class called Link.

A link is a connection between two resources, e.g., the resource
representing an issue is connected via a link to the resource representing a
collection of comments. An operation on the other hand describes a
(potential) HTTP request. I thus struggle to see how they could be combined.


> • The Resources have Methods not Links or Operations. Every Link

>   calls a Resource Method, and initiates a server side Abstract
>   Application State Transition.

Unless I misunderstand you here, I think I have to disagree. A resource can
be anything.. a document a person, whatever. There may be various
relationships between resources. For example, two persons might be friends.
Thus you have links (relationships) between resources:

  /Markus --[ knows ]--> /László

The "knows" here is the link relation type. As the name suggests, it defines
the type of relationship these two resources stand to each other. What
"Resource Method" does that link call? I don't know. Now I think you were
thinking more of something like

  /an-issue --[ comments ]--> /comments

right? Yeah, you as a human are smart enough to understand that you probably
can create a new comment by POSTing to the /comments URL because you
understand these string and know that it's a frequently used convention. A
machine isn't so smart. Thus we describe that with Hydra. We say whenever we
have a link with a relation type "comments" pointing to a resource, we may
create a new resource by POSTing an issue representation to that resource:

  {
    "@context": "http://www.w3.org/ns/hydra/context.jsonld",
    "@id": "#comments",
    "@type": "Link",
    "title": "Comments",
    "supportedOperations": [
      {
        "@type": "CreateResourceOperation",
        "title": "Creates a new comment",
        "method": "POST",
        "expects": "#Comment",
        "returns": "#Comment",
      }
    ]
  }

How would you propose to describe that instead? How would you combine links
and operations as you suggested above?


> • Two different Links can call the same Resource Method, they can

>   differ in the parameters of the Method. These parameters reflect
>   the different viewpoints of the different clients or the different
>   application states of the same client. I call that term Context,
>   but it can be called Aspect or ViewPoint as well. For example by
>   GET /users?offset=2&count=10 the GET /users is the constant part
>   and the ?offset=2&count=10 is the Context dependent part. So in

You are talking about IRI templates here. They are described in the spec as
well [3] but generally you can't say that "/users is the constant part". If
the server returns a IRI template that *might* be true but in a lot of cases
the server simply returns the complete URL and the client doesn't know how
to change it (you, as a human, can of course in a lot of cases).



>   this case the client want to display the user list, but in a
>   Context of 10 items per page and seeing the second page. Another
>   example is, while you are editing your profile on facebook, you
>   can watch it from different ViewPoints, you can see it as owner,
>   as acquaintance or as a stranger. The Context can contain the
>   following Request modifiers:
>

>   o identification factors for authentication
>   o sub-resource filters (pagination&sort, search keywords, filters

>     dependent on the authorization - the client should not know of
>     these)

>   o property filters (which fields to get from the server, or which

>     fields to set on a resource, it can be Context dependent, for
>     example a field is readonly by a regular user, but it is editable
>     by an admin...)
>
>   The Context can contain Link Relations as well, but those are not
>   sent to the server, so they are not Request modifiers. The API
>   documentation should describe them as well, because they are sent
>   back with the Hypermedia. So if you define supported Context params
>   by every Method and concrete Context params by every link, then the
>   PagedCollection and the Iri Templates will be obsolete.

You mean instead of using IRI templates you would move the parameters into
the description of operations? How would you describe a URL template like
this in that case:

  /users-{lastname]-{id}/

The resulting URL would thus be, e.g., /users-lanthaler-984/. It looks
compelling to define that parameters are to be treated as query parameters
but limiting it to that is too restricting in a lot of cases IMO.


> • I think it will be good to define a Representation class. The

>   Representations can contain Links and Representation of
>   Properties. I don't have a name for that term yet, but for example
>   you can represent a date many different ways, but you store it
>   usually one way in the resource, or you can represent a property

Typically, you would just type your data. E.g.

  {
    ...
    "modified":
    {
      "@value": "2010-05-29T14:17:39+02:00",
      "@type": "http://schema.org/Date"
    }
  }

The JSON-LD specification [4] describes this in more detail.



>   name many different ways, e.g. firstName, first-name, givenName,
>   név (in Hungarian), etc... The Resources can contain Methods and

Are you talking about the JSON property names here?



>   Properties. By creating a Documentation, we should describe the
>   relevant part of the Representations and the Resources as well.
>   The current vocabulary describes only the Resources well, but by
>   describing the Representations (which are the available options by
>   Resources restricted to the current ViewPoint of the client) there
>   are many different classes for the same problem domain
>   (TemplatedLink, IriTemplateMapping, IriTemplate, PagedCollection,
>   CreateResourceOperation, ReplaceResourceOperation,
>   DeleteResourceOperation), but not a single, which can generally
>   solve it (Representation, Context, Link with LinkRelations).

Sorry, I don't understand what you are saying here. Could you perhaps
illustrate it with an example and I'll try to explain how you can describe
it with Hydra.



> My REST vocabulary is currently a draft too, I have to create a proof
> of concept application, but I think its approach is more general than
> Hydra currently possess, so it could be part of the next release of
> Hydra. I was too tired to write a more detailed post about it, I am
> not sure whether this is understandable or not, please write a
> feedback.

Apart from the last part I think I understood what you meant. I think it
would help if you could briefly describe a number of use cases which aren't
supported (well) by Hydra but are by your draft because it is more general.
Does that sound like a reasonable way forward?


Cheers,
Markus


[1] https://github.com/HydraCG/Specifications/issues/24
[2] https://github.com/HydraCG/Specifications/issues/18
[3] http://www.hydra-cg.com/spec/latest/core/#templated-links
[4] http://www.w3.org/TR/json-ld/#typed-values


--
Markus Lanthaler
@markuslanthaler

 

Received on Tuesday, 28 January 2014 13:46:02 UTC