A well-designed HATEOAS API will have clear entry points, and the rest of the application behaviour will be discoverable from there.
Since the question is about HATEOAS specifically I would say using a URI template puts too much responsibility onto the client. Instead you should provide an explicit URL for each valid action on the resource given the current application state.
This isn't just a stylistic point. If the server provides a template then the client developer has to write code to populate the template, which creates a coupling between them. You can't change the server-side URL structure now without breaking the contract with its clients. With HATEOAS you associate a URL with each action allowed on a resource, and the client just cares about the action. The URL is effectively an opaque handle: "Choose your own adventure", as Ian Robinson says.
HATEOAS is about using hypermedia—media containing links to other media—to enable a client to navigate around an application with no other knowledge than the last response it received. That means each response should provide the client with ready-to-use URLs representing all valid actions on the current resource.
Remember, the thing-you-get-over-the-wire is only a representation of a resource (REST stands for REpresentational State Transfer). There can be different representations of the same resource based on your current context, say your current set of permissions, and the current application state. Different representations can legitimately offer different next actions.
Using your example, the owner of an order might see this:
{
"id": "/api/v1/orders/123", // reference to the current resource
"rel": {
"cancel": {
"url": "/api/v1/orders/cancel?order_id=123",
"method": "POST",
// Metadata about what the cancel operation returns...
},
"list_orders": {
"url": "/api/v1/orders",
"method": "GET",
// Metadata about what the list_orders operation returns...
},
// ...
// Other operations available to the owner
},
// ...
// Order state
}
Here I'm defining a map that uses the key as the operation name, or relation in HATEOAS terminology, although I could equally have a list of maps with a key called "rel"
and values of "cancel"
and "list_orders"
respectively.
Another role, say the shipping coordinator, may not see the cancel
operation because they den't have permission to cancel an order.