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.
HAL is a simple format that gives a consistent and easy way to hyperlink between resources in your API. The HAL format is strictly coupled to HATEOAS. The main target of HATEOAS is to decouple the API Consumer from the paths used in the API.
HATEOAS is a feature of the REST application architecture that allows you to navigate REST APIs just as easily as you can navigate websites. You can use HATEOAS to follow embedded URIs pointing to other resources to explore and interact with an API.
HATEOAS stands for Hypermedia as the Engine of Application State and it is a component of RESTful API architecture and design.
Hypermedia as the Engine of Application State (HATEOAS) is a constraint of the REST application architecture that distinguishes it from other network application architectures. With HATEOAS, a client interacts with a network application whose application servers provide information dynamically through hypermedia.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With