Comments (18)
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.
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.
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.
@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.
@RubenVerborgh Ah, that's reasonable.
from tent.io.
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.
I also have a ticket open (#14) explaining why profile
is a good idea.
from tent.io.
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.
@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.
@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
orDELETE
.
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 beAccept-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 theenctype
:<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 haveGET
,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.
@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.
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.
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.
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.
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.
@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.
It even uses the same terminology! http://amundsen.com/hypermedia/profiles/
from tent.io.
Ha, it says so at the bottom. Awesome.
from tent.io.
Related Issues (20)
- Idea: allow profiles to be requested on the new_post endpoint
- How to handle attachments with identical digests on a single post
- What Content-Type to return on the attachment endpoint
- Allow the attachment endpoint to redirect to a CDN location
- Why is the attachment endpoint needed?
- Relationship post type fragment
- Posts feed pagination issue
- Use of Cache-Control can be difficult in browsers HOT 2
- Allow a "types" parameter on the mentions endpoint
- Proposal: rename app.id to app.post
- Proposal: omit urls for not supported endpoints in meta post
- Provide a Status Update HOT 3
- Notification Status
- Will tor connectivity be enforced? HOT 3
- Definition of profile sturcture HOT 2
- Finish documentation HOT 2
- Meta posts' profile.website having a duplicate option or as an array. HOT 1
- Transaction post type HOT 1
- Community Issues: How to address the barrier to entry with prospective users? HOT 10
- tent is dead! What's the reason? HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from tent.io.