5

I'm learning about HATEOAS and I noticed that every implementation always seems to implement a self-relationship first. For example a common response object might look like

{
  title: "The Wonderful Wizard of Oz",
  author: "L. Frank Baum"
  links: [
    {
      rel: "self",
      href: "www.foo.com/book/1234"
    },
    {
      rel: "author",
      href: "www.foo.com/author/4321"
    }
  ]
}

Why is the self relationship always there? It seems utterly useless to me. As a client who just made the request to get the response object I would obviously know the URL to get the object. Why is it presented?

2
  • 2
    Suppose you didn't just make the request. Perhaps the JSON is sitting in some state variable you are examining, or you printed it out. How else would you know what endpoint it came from? Jun 20, 2017 at 18:12
  • It might interest you
    – Laiv
    Jun 20, 2017 at 20:50

3 Answers 3

6

The self link is also used for embedded entities where it can be used to navigate to the proper entity. See this HAL example:

{
    "_links": {
        "self": { "href": "/orders" },
        "curies": [{ "name": "ea", "href": "http://example.com/docs/rels/{rel}", "templated": true }],
        "next": { "href": "/orders?page=2" },
        "ea:find": {
            "href": "/orders{?id}",
            "templated": true
        },
        "ea:admin": [{
            "href": "/admins/2",
            "title": "Fred"
        }, {
            "href": "/admins/5",
            "title": "Kate"
        }]
    },
    "currentlyProcessing": 14,
    "shippedToday": 20,
    "_embedded": {
        "ea:order": [{
            "_links": {
                "self": { "href": "/orders/123" },
                "ea:basket": { "href": "/baskets/98712" },
                "ea:customer": { "href": "/customers/7809" }
            },
            "total": 30.00,
            "currency": "USD",
            "status": "shipped"
        }, {
            "_links": {
                "self": { "href": "/orders/124" },
                "ea:basket": { "href": "/baskets/97213" },
                "ea:customer": { "href": "/customers/12369" }
            },
            "total": 20.00,
            "currency": "USD",
            "status": "processing"
        }]
    }
}

The only rationale I could think of for having self links on top-level entities is that if you enter the service at some arbitrary entity, the self link gives you information about your context in the service. In the example above if somebody gave me a link to http://example.com/myservice/special/dev/2017/admins/2, the self link relative to the service root (/admins/2) would be useful for finding the root of the service and understanding that there are probably more admins, etc.

1

Why is the self relationship always there? It seems utterly useless to me. As a client who just made the request to get the response object I would obviously know the URL to get the object. Why is it presented?

Because the identifier that you used to obtain the current representation may not be the preferred identifier.

The link relation registry cites RFC 4287 as the reference for the "self" link relation. In RFC 4287, you will find:

Section 4.1.1

atom:feed elements SHOULD contain one atom:link element with a rel attribute value of "self". This is the preferred URI for retrieving Atom Feed Documents representing this Atom feed.

Section 4.2.7.2

The value "self" signifies that the IRI in the value of the href attribute identifies a resource equivalent to the containing element.

0

In addendum to Samuel's answer, the self links also exist in aggregate collections. It would make sense from my perspective for the aggregate collection to compose itself using the same logic that an individual entity does, for all entities in the collection. So if a foo resource calls showFoo when a single foo is requested, showAllFoos will internally call showFoo for each foo. It does not make much sense to add more logic to remove the self link when only a single entity is requested within showFoo.

Additionally, a more general tip about creating integration points is to follow the principle of least astonishment. If your discoverable service is meant to advertise a list of all endpoints of a resource, it should hold a list of all of the endpoints for that resource when it is requested and not all of the endpoints that some developer thought you might actually need.

Both of these reasons are more in tune with general software development principles and are not specific to REST design.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.