REST/HATEOAS - Available methods in HAL links
Asked Answered
G

2

13

I am looking at defining a REST API using HATEOAS. In particular, I find very interesting the concept of indicating for a given resource the actions that are available right now.

Some of the HATEOAS specifications include too much overhead for my needs, so I was looking at the HAL specification, as I find it very concise and practical:

{
    _links: {
        self: { href: "/orders/523" },
        warehouse: { href: "/warehouse/56" },
        invoice: { href: "/invoices/873" }
    },
    currency: "USD",
    status: "shipped",
    total: 10.20
 }

However, links in HAL only contain a list of related resources, but not the available actions on them. As per the example above, am I allowed to cancel the order now, or not anymore? Some HAL examples solve this by using a specific URL for cancellations, and add a corresponding link in the response only if cancellation is possible:

"cancel": { "href": "/orders/523/cancel" }

But that is not very RESTful. Cancellations are not a resource. Cancellations are a DELETE of a resource, i.e.:

DELETE /orders/523

Is there a nice way to represent this with HAL, or should I use a different HATEOAS specification?

I am considering returning a "cancel" link with the same URL as self, but in this case the client would have to know that to cancel they have to use the DELETE verb, which is not really being described in the HATEOAS response.

self: { "href": "/orders/523" },
cancel: { "href": "/orders/523" }

Would this be the recommended approach as per HATEOAS / HAL? I understand HAL does not have any "method" parameter, and adding it myself would be against the HAL specification.

Gamophyllous answered 6/7, 2017 at 9:18 Comment(0)
F
9

Some HAL examples solve this by using a specific URL for cancellations, and add a corresponding link in the response only if cancellation is possible

Yes. Just like web sites: if you want to alert the client to the possibility of reaching some other application state, you provide the client with a link, including the identifier for the resource involved.

But that is not very RESTful.

It may not be "RESTful", but it is certainly conforms to the REST architectural style.

Cancellations are a DELETE of a resource, i.e.: DELETE /orders/523

You are confusing the actions on the domain model with the actions on the integration model. What a REST API does is guide the client through a protocol to achieve some end; it is not a mapping of domain semantics onto HTTP.

Jim Webber phrased it this way:

The web is not your domain; it's a document management system. All of the HTTP verbs apply to the document management domain. URIs do NOT map onto domain objects -- that violates encapsulation. Work (ex: issuing commands to the domain model) is a side effect of managing resources.

One of the REST constraints is the uniform interface; in the case of HTTP, it means that all resources understand methods in a uniform way; DELETE means the semantics described in RFC 7231, section 4.3.5.

In other words, if I send the request

OPTIONS /x/y/z/foobar ...

and the response includes DELETE in the Allow header, then I know what it means. The side effects in your domain? I don't know anything about the side effects.

In the definition of DELETE, note the following

Relatively few resources allow the DELETE method -- its primary use is for remote authoring environments, where the user has some direction regarding its effect.

Anyway, you aren't really asking about DELETE, but about HAL

Is there a nice way to represent this with HAL, or should I use a different HATEOAS specification?

From what I can tell, the official way to do it is to document it with the link relation. In other words, instead of using "cancel" as the link relation, you use something like

https://www.rfc-editor.org/rfc/rfc5023#section-5.4.2

And then your consumers, if they want to discover what a link is for, can follow the relation to learn what is going on.

HAL Discuss: Why No Methods? has a lot of good information.

I like Mike Kelly's summary:

The idea is the available methods can be conveyed via the link relation documentation and don't need to be in the json messages.

Follett answered 6/7, 2017 at 13:29 Comment(2)
Great answer as always :) According to the usage of link relation names I'd probably follow the approach outlined in RFC 5988 (Web linking) and either make use of registered relation types or extension types such as Dublin Core or schema.org, which require URIs similar to the example given in the answer, which is also recommended by HAL+JSON.Fatigue
Great answer, I think the OPTIONS method is the correct place to store the available operations for the Rest resource.Donyadoodad
T
1

According to this article from LosTechies, in a CQRS perspective, Its accepted to use URLs such as: /orders/<id>/<command> and call these with PUT requests. So its OK to use a "cancel": { "href": "/orders/523/cancel" }.

However, if you absolutely want to use DELETE and you only use command links to modify your ressources (i.e. /orders/<id>/<command>) like proposed the article, why can't you just add a link such as "cancel": { "href": "/orders/523" } and deduct the HTTP verb? I mean according to REST there is only 5 main verbs (GET, POST, PUT, PATCH and DELETE). We can't use POST on a URL such as /<ressource>/<id>, GET is already define as the "self" relation, we mentioned above that modifications (PUT) will be handled by command links (i.e. /<ressource>/<id>/<command>) and because we use command links there is no need to use PATCH. After that, the only option left is: DELETE.

It's not perfect, but it works and it doesn't break any convention.

Telephone answered 14/3, 2019 at 16:23 Comment(4)
... according to REST there is only 5 main verbs ... REST doesn't specify any of these, it just mentions a couple operations within the disseration itself, POST i.e. doesn't appear in the context of HTTP at all. As HTTP methods are standardized and maintained by IANA there are actually a couple more you should consider supporting, at least they are propper HTTP methods even when not widely used.Fatigue
@RomanVottner I'm talking about the accepted REST conventions and good practices. KevinDockx did a great course on that at pluralsight: app.pluralsight.com/library/courses/…Unship
... accepted REST conventions and best practices ... by whom? Typical conventions state that verbs like cancel shouldn't be put in a URI as the action should be expressed by the HTTP operation when Fielding's dissertation doesn't put such a constraint in to start with. In reallity the characters in an URI doen't matter in an archtecture that uses the REST interaction model, though plenty people seem to beliefe that this is "not RESTful". Such "conventions" should be treated with care as they depict the opinion by some but not necessarily the truthFatigue
@RomanVottner [...] by whom? Typical conventions state that verbs like cancel shouldn't be put in a URI as the action should be expressed by the HTTP operation [...]. JimmyBogard do it in this article: lostechies.com/jimmybogard/2016/06/01/…Unship

© 2022 - 2024 — McMap. All rights reserved.