Question

I am in the process of designing a custom media type for a RESTful API, and have researched the types and semantic meaning of the some of the 'standard' link relations to give my design some steer.

To demonstrate the problem let's say that I have a resource that I can perform standard read, change, delete methods on and that I use the HTTP idioms of GET, PUT and DELETE respectively to implement those methods.

I could reasonably (re)use the "edit" link relation (from the IANA link registry) as defined in RFC5023 which states:

"...The value of "edit" specifies that the value of the href attribute is the IRI of an editable Member Entry. When appearing within an atom:entry, the href IRI can be used to retrieve, update, and delete the Resource represented by that Entry...."

In this way, the user-agent can understand that a link with a "edit' relationship, will allow the resource to be GET, PUT and DELETEd.

However, and herein lies the problem, if the resource state is edited such that the resource now supports only GET and DELETE operations, the "edit" relation is no longer precise.

In order to retain the precision I need to either i) OPTION A: specify another (compound) link relation that supports GET & DELETE only, or ii) OPTION B: specify individual links for each possible state transfer and use the appropriate ones to indicate the permitted state transfers. The latter approach offers precision but seems overly verbose.

Alternatively, (OPTION C) I could leave the "edit" relationship in place and accept the lack of precision i.e. the link would convey the GET, PUT, DELETE semantics but a user-agent attempting a PUT would be met with an HTTP error '405 - Method not allowed'. However, I'm not happy with this approach either as it implies to the client a state transition which is not supported.

In summary, the question is what is the most sensible way to balance link relation generality and precision?

Was it helpful?

Solution

After some serious investigation I conclude that I'm trying to solve the wrong problem. Rather than be concerned with the granularity of HTTP verb in the definition of the Link Relation, a more refined question is 'Should the HTTP idioms (verbs) be conflated into the Link Relation?'.

I had used AtomPub as a reference of how to do Link Relations (for REST) and it turns out that this was an error. In the AtomPub mail archive Roy Fielding advises that (in REST terms) the approach to 'edit' is wrong and concludes that it is unnecessary. The argument suggests that there are other (HTTP) mechanisms to convey such properties and that they therefore have no place in 'rel' attribute.

The other mechanisms aren't made explicit in the mail archive, but I suspect they include the following options:

  1. Let the user-agent try and examine the response (2xx or 4xx), or
  2. Use OPTIONS to ask the resource for the permitted operations, or
  3. Include an 'Allow' header in successful GET requests to convey permitted resource operations to the user-agent.

Interestingly, Roy considers the 'Allow' header to be "a form of hypertext".

In summary, the answer to my own question is:

"Do not conflate HTTP operations into the meaning of 'rel' "

and

"Use the (provided) HTTP mechanisms to determine permitted resource operations"

Edit: I should add that there are some special uses of POST as data sink where these rules need to bent a little, but then they are a special case.

OTHER TIPS

The WRML specification takes an approach where each "link" object can have a rel property.

GET /dogs/1
{
    "links" : {
        "self" : {
            "href" : "http://api.example.com/dogs/1
            "rel" : "http://api.example.com/relations/self"
        }
    }
}

And the client can then follow the rel url

GET /relations/self
{
   "name" : "self"
   "description" : " A reference back to the same object you are currently interacting with" 
   "method" : "GET"
}

The spec does recommend that each rel should have exactly 1 method specified. This has the enefit of being very explicit with your clients what they should do, and limits the amount of out of band knowledge that is required. I personally go back and forth on this, because I think there is some value in saying that certain "rel" provide multiple HTTP methods. Imagine a link for the owner of the dog

GET /dogs/1
{
    "links" : {
        "self" : {
            "href" : "http://api.example.com/dogs/1
            "rel" : "http://api.example.com/relations/self"
        }
        "owner" : {
            "href" : "http://api.example.com/owner/1
            "rel" : "http://api.example.com/relations/owner"
        }
    }
}

It would be nice to let "owner" imply GET and PUT since those are both valid actions. THe counter to that is you should always need to do a GET before doing an update so the value in giving that information prior to retrieving the resource is bad form.

So I guess all that said I would vote for OPTION B.

Another option would be to leave the "edit" relation, and allow a consumer who wants to know what they can currently perform on the resource to make a request with an OPTIONS HTTP method and the server can return a response with an Allow header to indicate the allowed methods on the resource given it's current state.

It doesn't give you the availability of the PUT operation without an extra request, but is fairly "clean" and lets you use a standard relation and HTTP mechanism.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top