Giter VIP home page Giter VIP logo

Comments (18)

beberlei avatar beberlei commented on September 10, 2024

My problem with the REST Part of the document is,that it is not REST all to the send, see http://martinfowler.com/articles/richardsonMaturityModel.html

Hypermedia and Link relations are missing and there is already the creep of "version" in every post-type that prematurely tries to solve this problem with a messy solution. For example, the schema url of the post-type already acts as the version "http://example.com/my-proto" and "http://example.com/my-proto+v2". Please reconsider replacing the "url" with the XML notion of uri to allow for actual content-types.

from tent.io.

RubenVerborgh avatar RubenVerborgh commented on September 10, 2024

It would be straightfoward to add hypermedia links to many resources, to avoid the URI construction that happens now.
Instead of Tent-Server, it would probably be more beneficial to just use the HTTP Link header, so instead of:

Tent-Server: https://tent.titanous.com

you get:

Link: <https://tent.titanous.com/profile>; rel="profile"

No need for a new header type, plus the link goes directly to the profile.

Other opportunities to add links are from the profile resource to the followers and notifications resources.
These links could either be included in the HTTP Link header (which already has the right semantics),
or you could define link semantics in your media type (#11).

from tent.io.

titanous avatar titanous commented on September 10, 2024

I'm open to using hypermedia links instead of building URLs. Due to Tent supporting multiple servers, this would require listing all the available options (one link for the resource on each server) and the links in cached data would get stale if a user changed servers. It does seem like the staleness could be worked around by using standard HTTP caching directives, though.

@beberlei We'll evaluate switching to version uris that can double as media types.

@RubenVerborgh I'm not opposed to switching to a Link header, but should the rel be profile? It seems pretty generic, and doesn't specify that it's a Tent profile, which makes discovery more complicated.

from tent.io.

RubenVerborgh avatar RubenVerborgh commented on September 10, 2024

@titanous There is always the possibility of adding type information to the link, like so (just an example):

Link: <https://tent.titanous.com/profile>; rel="profile"; type="application/json+tent"

Being generic is the good part about the profile relation type ;-)

from tent.io.

titanous avatar titanous commented on September 10, 2024

@RubenVerborgh Ah, that's reasonable.

from tent.io.

beberlei avatar beberlei commented on September 10, 2024

Custom mime-types are supposed to be in the format "application/vnd.company.type+format", so in this case "application/vnd.tent.io.profile+json"

from tent.io.

steveklabnik avatar steveklabnik commented on September 10, 2024

I also have a ticket open (#14) explaining why profile is a good idea.

from tent.io.

camshaft avatar camshaft commented on September 10, 2024

Moving to a hypermedia driven architecture would allow the servers to be completely backwards compatible. A RESTful api should be able to set all of its own end points and the client should only know about the root (see here). I would HIGHLY recommend reading Building Hypermedia APIs by Mike Amundsen to understand the full potential of building a scalable distributed architecture using hypermedia. You can see his sample code here.

from tent.io.

titanous avatar titanous commented on September 10, 2024

@camshaft I don't have time to read a book about this, so someone on this issue is going to have to explain this to me.

If someone could take a request/response from the Tent docs and modify it to use hypermedia it might help me understand where you are coming from.

Tent posts are expected to be immutable and permanently cached after they are pushed out to other servers. On the other hand, server domains/urls are expected to change, and we are anticipating cases where there are several different fallback/alternative API roots. I haven't seen an example so far, but the suggestion as I understand it is to bundle links to with resources like posts, these would become stale in some use cases that we are optimizing for.

Moving to a hypermedia driven architecture would allow the servers to be completely backwards compatible.

I'm skeptical of this claim. I've created and maintained real-world APIs used by a lot of developers, and the issue has never been keeping track of resource paths. Backwards compatibility tends to be broken by changes in the keys/values in resources, not because a resource moved and the client can't find it.

from tent.io.

camshaft avatar camshaft commented on September 10, 2024

@titanous I would love to offer an explanation:

Hypermedia == Rest
In his dissertation, Roy Fielding addressed the need of managing state in a
distributed system in a scalable way. He came up with some constraints in order
to accomplish this (source):

  • Client–server
  • Stateless
  • Cacheable
  • Layered system
  • Code on demand (optional)
  • Uniform interface

When we talk about uniform interface that means we have a standard way of interacting
with the server. The client should not have previous knowledge of how to
interact with a particular server beforehand and should be able to discover
interactions based on the Hypermedia.

Mike Admunsen puts it this way:

Hypermedia payloads carry two types of vital metadata: metadata about the
data itself and metadata about the possible options for modifying the
state of the application at that moment.

Because of this constraint, a RESTful/Hypermedia api MUST be driven by
hypermedia. Unfortunately, a lot api's on the web violate this.

So the question now becomes how do we use hypermedia to drive state. In order
to understand that, we need to have a combination of what Mike Admunsen calls
H-Factors. They are as follows:

  • Links

    • LE Embed Links

      Embedded links allow you to embed content. A perfect example is the <img>
      tag in HTML. This instructs the client to present the image to the user
      along with the payload

      ```html
      <img src="..." />
      ```
      
    • LO Outbound Links

      Outbound links link externally to another resource. Anchor (<a>) tags do
      exactly this:

      ```html
      <a href="...">...</a>
      ```
      
    • LT Templated Links

      Templated links give the client the ability to query the server for
      information. This can be in the form on a <form> tag:

      ```html
      <form method="get" action="http://www.example.org/">
        <input type="text" name="search" value="" />
        <input type="submit" />
      </form>
      ```
      

      or using an <a> tag:

      ```html
      <link href="http://www.example.org/?search={search}" />
      ```
      

      This way the client doesn't know the parameters outside of the request
      context.

    • LI Idempotent Links

      Speaking in context of HTTP these are links that require a PUT or DELETE.
      Two ways to provide this type of link is through a <form>:

      ```html
      <form method="delete" action="http://www.example.org/comments">
        <input type="text" name="id" value="" />
        <input type="submit" />
      </form>
      
      // If the client doesn't support delete in a form you can offer
      // code-on-demand
      <script type="text/javascript"> 
        function delete(id) {
          var client = new XMLHttpRequest();
          client.open("DELETE", "http://example.org/comments/"+id);
        }
      </script>
      ```
      

      or an <a> tag:

      ```html
      // This comes from the Atom media type
      <link rel="edit" href="http://example.org/edit/1"/>
      ```
      
    • LN Non-Idempotent Links

      This link, in HTTP context, uses POST:

      ```html
      <form method="post" action="http://example.org/comments/">
        <textarea name="comment"></textarea>
        <input type="submit" />
      </form>
      ```
      
  • Control Data

    These are specific to the Protocol you are using, HTTP in our case

    • CR Read Controls

      Allows the client to control the way it reads information from the server.
      In HTTP, for example we can set our header to be

      Accept-Language: da, en-gb;q=0.8, en;q=0.7
      

      And the response should be served up in a different format

    • CU Update Controls

      This allows the client to specify the way it writes to the server. For
      example, in a form it could specify the enctype:

        <form method="post" action="http://example.org/comments/" enctype="text/plain">
          <textarea name="comment"></textarea>
          <input type="submit" />
        </form>
    • CM Method Controls

      This is determined by the protocol the hypermedia is being sent over.
      In HTTP, we have GET, POST, PUT, DELETE, etc...
      Both the client and the server know about these methods and know
      how to execute them

    • CL Link Annotation Controls

      These controls provide annotations/metadata for the actual links. For
      example when we link a stylesheet to a html document we use

        <link rel="stylesheet" href="..." />

      specifying the type of content that the link provides

With these H-Factors in place, we can successfully design a REST/Hypermedia API
example. I'll be forking the specs and giving a concrete example. I'll let you
know as soon as I'm done.

Let me know if you have any questions. BTW, I think this is an awesome idea
and would love for this to take off. Keep up the good work.

from tent.io.

camshaft avatar camshaft commented on September 10, 2024

@titanous Also backing up my claim of

Moving to a hypermedia driven architecture would allow the servers to be completely backwards compatible.

Let's say a client consumes the entity https://titanous.me. This is a basic client that allows you to post content to
the server and get it back.

Let's setup two scenarios: one where the client is implemented with the current implementation and another using hypermedia:

Current

Client makes a request:

POST /posts HTTP/1.1
Host: https://titanous.me
Content-Type: application/json
Length: XX

{
  ...
  "content": {
    "type": {
      "url": "https://tent.io/types/posts/status",
      "version": "0.1.0",
      "view": "full"
    },
    "text": "Necessitatibus saepe exercitationem. Quidem rem aspernatur atque numquam in. Voluptas qui et.",
    "excerpt": "Necessitatibus saepe exercitationem..."
  ...
}

and the server responds with

HTTP/1.1 201 Created

The problem with this is the client knows about the body previously and has to form the url on it's own. Because of this, if we add property foo and make it required:

{
  ...
  "content": {
    "type": {
      "url": "https://tent.io/types/posts/status",
      "version": "0.1.0",
      "view": "full"
    },
    "text": "Necessitatibus saepe exercitationem. Quidem rem aspernatur atque numquam in. Voluptas qui et.",
    "excerpt": "Necessitatibus saepe exercitationem...",
    "foo": "bar"
  }
  ...
}

all of the clients using our server will break because they have no knowledge of the new parameter we added.

Hypermedia Implementation

Client makes a request:

GET / HTTP/1.1
Host: https://titanous.me

The server responds:

HTTP/1.1 200 OK
...

<!DOCTYPE html>
<html>
  <head>
    <title>Tent.io</title>
  </head>
  <body>
    <div id="queries">
        <ul class="nav">
          <li>
            <a rel="profile" href="https://titanous.me/profile" title="Profile">Profile</a>
          </li>
          <li>
            <a rel="followers-list follow unfollow" href="https://titanous.me/followers" title="Followers">Followers</a>
          </li>
          <li>
            <a rel="notify" href="https://titanous.me/notifications" title="Notifications">Notifications</a>
          </li>
          <li>
            <a rel="posts-list post-create" href="https://titanous.me/posts" title="Posts">Posts</a>
          </li>
        </ul>
    </div>
    ...
  </body>
</html>

Our client would read this and look for the <a> tag that says post-create and follow it:

GET /posts HTTP/1.1
Host: https://titanous.me

Response:

HTTP/1.1 200 OK

<!DOCTYPE html>
<html>
  <head>
    <title>Tent.io</title>
  </head>
  <body>
    <div id="queries">
    ...
    </div>
    ...
    <form class="post-create" method="post" action="/posts">
      <select name="view">
        <option value="full">Full</option>
        ...
      </select>
      <input type="text" name="text">
      <input type="text" name="excerpt">
      <input type="submit" value="Post">
    </form>
  </body>
</html>

The client would read the response and search for the form .post-create. It would present all of the inputs listed in the form
to the user and pass them back

POST /posts HTTP/1.1
Host: https://titanous.me
Content-Type: application/x-www-form-urlencoded
Length: XX

text=this+is+my+post&excerpt=this+is+an+excerpt...

and the server responds

HTTP/1.1 201 Created
Location: https://titanous.me/posts/postid

Even though this interaction is chattier, it is much more scalable. Let's say we make the same change to the required fields by adding foo. Foo would show up in our form as

HTTP/1.1 200 OK

...
    <form class="post-create" method="post" action="/posts">
...
      <input type="text" name="foo">
...
      <input type="submit" value="Post">
    </form>
...

The client wouldn't act any differently or even notice a difference. It would read the response, present the form to the user, and take the user's fields and send them to the server through the action. With this method, clients can be written once and never updated but still be able to interact with brand new servers.

Backwards compatibility is achieved because the client is not bound to a previously know data format.

from tent.io.

camshaft avatar camshaft commented on September 10, 2024

This is the last comment for now but I figured people are going to comment on this so I'll defend it before. I chose to use HTML as my media type in my examples because it has 7 out of the 9 H-Factors we need without customizing the media type. If we are wanting to use json i recommend json-hypcos. The server could potentially support both through the accept/content-type headers. For further reading you can check out http://amundsen.com/hypermedia/

from tent.io.

lanthaler avatar lanthaler commented on September 10, 2024

Please note that the Tent-Server header can _not_ be replaced with an profile Link header. The purpose of the Tent-Server header is to point to the API root whereas a profile Link header is used to associate a number of conventions/semantics on top of a media type. You could therefore see it as a more fine-grained way to label a response with a media type. Therefore also using a custom media type plus a profile header makes absolutelty no sense.

from tent.io.

RubenVerborgh avatar RubenVerborgh commented on September 10, 2024

I'm not sure about that, but it doesn't change the case for the Link header, maybe with another type value though.
No reason to use Tent-Server.

The profile specification draft, however, doesn't seem to exclude the possibility of using profile for this purpose:
This specification defines the 'profile' link relation type that allows resource representations to indicate that they are following one or more profiles. A profile is defined to not alter the semantics of the resource representation itself, but to allow clients to learn about additional semantics (constraints, conventions, extensions) that are associated with the resource representation, in addition to those defined by the media type and possibly other mechanisms.

from tent.io.

camshaft avatar camshaft commented on September 10, 2024

The profile link would probably point to something like this.
Like @RubenVerborgh explained, it would describe the semantics of the media type.

from tent.io.

lanthaler avatar lanthaler commented on September 10, 2024

@RubenVerborgh, I'm not arguing against using a Link header, actually I already filed a pull request last week to change this: Pull Request #35. What I'm saying however is that a a profile link is not an adequate replacement. The target of a profile Link header is not a pointer but an identifier. So, it is not expected to be dereferenced but intented to be used as an identifier in order to be able to process a response correctly.

The purpose of the current Tent-Server header is to point to the API root of a Tent server, i.e., the target would be different for every single Tent instance. The whole point of the profile header is to keep it constant to be able to associate additional conventions/semantics to an existing mime type.

from tent.io.

steveklabnik avatar steveklabnik commented on September 10, 2024

It even uses the same terminology! http://amundsen.com/hypermedia/profiles/

from tent.io.

steveklabnik avatar steveklabnik commented on September 10, 2024

Ha, it says so at the bottom. Awesome.

from tent.io.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.