Skip to content

Instantly share code, notes, and snippets.

@odrotbohm
Created April 26, 2012 07:21
Show Gist options
  • Save odrotbohm/2497116 to your computer and use it in GitHub Desktop.
Save odrotbohm/2497116 to your computer and use it in GitHub Desktop.
Spring Data REST - Link representation options
1. Current state (1.0.0.M1)
---------------------------
+ Aligned with the XML definition of atom:link.
- Harder to work with for JavaScript clients
GET /root
200 OK
{ _links : [ { rel : "persons", href : "/root/persons" },
{ rel : "accounts", href : "/root/accounts" }]}
2. Alternative
--------------
+ Easier to work for JavaScript clients.
- Custom link scheme introduced
- Multiple links with same rel impossible (see below)
GET /root
200 OK
{ _links : { persons : "/root/persons",
accounts : "/root/accounts" }}
3. Problematic scenario with 2.
-------------------------------
A GET to a collection resource currently returns a list of links, not representations, which would create duplicated keys for the fields.
GET /root/persons
200 OK
{ _links : { person : "/root/person/1",
person : "/root/person/2" }}
This is of course invalid but we could tackle this problem in two ways:
3.1. Plain link lists without rels
----------------------------------
As the rel for the returned links is implicitly known by the collection resource (a GET to a persons resource, returns links pointing to person resources). We could simply return a list of links then:
GET /root/persons
Accept: application/json
200 OK
[ "/root/person/1", "/root/person/2" ]
or
200 OK
{ _links : [ "/root/person/1", "/root/person/2" ] }
GET /root/persons
Accept: text/uri-list
200 OK
/root/persons/1
/root/persons/2
3.2. Return representations instead of links
--------------------------------------------
Alternatively we could return a more verbose representation of the persons already:
GET /root/persons
200 OK
{ persons : [ { firstname : "Dave",
lastname : "Matthews"
_links : { self : "/root/persons/1" }},
{ firstname : "Carter",
lastname : "Beauford",
_links : { self : "/root/persons/2" }
],
_links : { _next : "/root/persons?page=1&size20" } }
We did not decide for that approach in the first place as if done naively we might return all the resources which results in an unbearable payload and unnecessary network traffic. An approach to work around this is paging by default, which means we will return only a subset of the resources by default and provide links to navigate the collection.
@kdonald
Copy link

kdonald commented Apr 26, 2012

I like links, I just haven't considered 'self' one of the links. Yes, custom mime types are often used for versioning. Github's v3 API does that, see http://developer.github.com/v3/mime/. My point was mostly about scope and that the scope of the Spring Data REST project should probably include support/guidance for resource representations and versioning. My other suggestion would be to have good JS client examples in the interest of keeping the project practical/pragmatic.

@kdonald
Copy link

kdonald commented Apr 26, 2012

Here's one for you. Say you have the following association: a GroupMember is associated with exactly one Account. Now lets say you GET a GroupMember. It's expected a JS client might want to retrieve the HTML view of the Account as well as the JSON representation of the Account. Here's the rub: these two representations are hosted on different hosts: the former, http://www.domain.com, and the latter http://api.domain.com. How would you model the links? Would you do the following:

{
  name: "Ollie",
  links: {
    account: "http://api.domain.com/accounts/1",
    account_site: "http://www.domain.com/olivergierke"
  }
}

or maybe:

{
  name: "Ollie",
  account: {
    links: {
      self: "http://api.domain.com/accounts/1",
      site: "http://www.domain.com/olivergierke"
    }
  }
}

Or something else?

Github uses url and html_url in their v3 API (it doesn't use a links bucket for data that are links).

@odrotbohm
Copy link
Author

Well, that feels kind of weird. From what you describe it seems like it's the same resource but effectively it isn't so the I'd effectively vote for the former although the common prefixes imply some correlation that from a REST point of view does not exist. So essentially the fact that it's logically the same resource with a different representation becomes a side aspect given the fact you expose these resources through different hosts. I'd argue this is where the benefits of HTTP infrastructure could come into place as well. Assuming you can map from ont URI to the other you could let a single server route the requests with Accept header application/json to some other server, whereas Accept of text/html is served directly or the other way round.

@kdonald
Copy link

kdonald commented Apr 26, 2012

It may feel weird but this is a very common case and question you will need to answer. I tend to agree treating them as separate resources is the right way to go. Nearly all the major APIs on the web separate out their API from their web site. Facebook, Twitter, Github, etc. So in those cases they're separate resources. Having complexity introduced at the HTTP routing layer in the name of REST "purity" smells of overengineering and unnecessary complexity to me. Browser Accept Headers also can't generally be relied upon, and a dedicated API subdomain separate from www is often desired.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment