Handling write only resources in a HATEOAS based REST api - rest

Let's assume I have a REST resource for my users. If the client requests one specific user with GET, the api returns the following json.
GET https://localhost:8080/api/user/xy
{
"name": "John Smith",
...
"_links": [{
"rel": "self",
"href": "https://localhost:8080/api/user/xy"
},
{
"rel": "changepassword",
"href": "https://localhost:8080/api/user/xy/password"
}]
}
As you can see the api provides a reference (in the _links section) to a resource where the client can change the password. I expect now the client to update the password when sending a PUT request to this reference.
Now my questions:
Is this a good/correct approach to implement a use-case like "change password" in a HATEOAS based REST api? Or is there another/better approach?
What should the server return after changing the password successfully? I would probably expect the status 204 and an empty body.
For sure I don't want to show the user his current password. Therefor my server will return a code 405, if the client is trying to GET the password resource. Is it generally valid to have a "write only" resource in a REST api?

... in a HATEOAS based REST api
First things first, one of the few constraint REST implies is that HATEOAS is already in place and therefore HTTP clients use links to progress its current state. A client not utilizing HATEOAS is not a REST client as well as an API not including links offering a clinet new state-possibilities is not a RESTful API!
Concerning your actual questions, it always depends on how you model certain things. You can use PUT to update the field and then return a 204 No Content response to indicate that this field has no readable content. According to the Spec
If the target
resource does have a current representation and that representation
is successfully modified in accordance with the state of the enclosed
representation, then the origin server MUST send either a 200 (OK) or
a 204 (No Content) response to indicate successful completion of the
request.
returning a 204 No Content status code is eligible.
An other approach could send the old password to the service in order for the service to first check the current password against the provided old one and only then update the password. This might prevent attacks which try to alter the passwords of other users in case you do not use an encrypted connection anyways. In order to achive this validation check however the client is not able to use a simple PUT operation anymore unless you make the old password part of the new state. Here POST is probably better suited as it leaves the semantics to the implementor of the API. This can go as far as to maintain a history of the last n passwords which the new password may not be any of the former ones.
HTTP offers the OPTIONS method a client can use to determine which operations are suitable for certain endpoints. Zac Stewart explained the usefulness of the OPTIONS method in regards to RESTful APIs in a blog post, and also points out the current shortcommings plenty of HTTP server have in regards to the usage of OPTIONS.
Most HTTP frameworks will return a 405 Method Not Allowed response code in cases an endpoint is invoked with an operation that has no implementation by default. At least in Java either in Spring MVC/Rest data or in JAX-RS methods offered at certain endpoints have to be annotated with interfaces that correspond to HTTP methods. Invoking an endpoint with an operation that has now equivalent annotated method will produce a 405 error response automatically, though this might be language and framework dependant.

Related

To PUT, POST or PATCH?

I have a REST Service that can be used to control databases, I want to allow calls to Stop & Start the databases, but was wondering what would be the correct Method?
By calling the Stop or Start Operation I am changing the state of the resource so a PUT seems sort of right, but is PATCH better or even POST?
Any suggestions?
Replacing the state of a resource
REST is protocol independent and is a resource-oriented architecture. When implementing REST applications over the HTTP protocol, for example, the resource is identified by the URI and the operation over the resource is expressed by the HTTP method.
PUT is the HTTP method used to replace the state of a resource and the new state of the resource will be expressed in the request payload using, for example, JSON and/or XML.
So you could consider the following design to start/stop a database:
PUT /databases/:id/status HTTP/1.1
Content-Type: application/json
{
"value": "started"
}
PUT /databases/:id/status HTTP/1.1
Content-Type: application/json
{
"value": "stopped"
}
To obtain the state of a resource, use GET:
GET /databases/:id/status HTTP/1.1
Response status codes
You certainly will need to inform your client about the result of the operation. To do it, use the HTTP response status codes.
A few status that might be useful:
200: Use this status to indicate that the request has succeeded.
202: Use this status code to indicate the request has been accepted for processing, but the processing has not been completed.
204: Use this status code to indicate the server has successfully fulfilled the request and that there is no additional content to send in the response payload body.
409: Use this indicates that the request could not be completed due to a conflict with the current state of the target resource.
Jim Webber explains that "HTTP is the application protocol of transferring documents" The transitions of state in your application are a side effect triggered by the document transfer.
Think old fashioned paper driven business office: the boss comes along and drops a TODO message in your inbox, which says "stop the database". As a side effect, you swivel your chair around and initiate the clean shutdown procedure.
Idiomatically, therefore, the representation you are sending to the REST server is that of the TODO message, and you are sending it to either (a) a resource that represents the "inbox" -- ie, a specific collection of TODO messages -- or (b) a resource that represents the TODO document itself.
I have a REST Service that can be used to control databases, I want to allow calls to Stop & Start the databases, but was wondering what would be the correct Method?
By calling the Stop or Start Operation I am changing the state of the resource so a PUT seems sort of right, but is PATCH better or even POST?
Since you are sending a complete message, rather than trying to make a modification to a message that the REST server already knows about, PATCH is not appropriate.
DELETE is also not appropriate - delete is analogous to destroying the TODO message in the inbox.
If the media type that you are using to represent application state at the client is HTML, then the verb you use shall be POST, because HTML doesn't support PUT.
If you are delivering a representation of a single message to a resource that represents a collection, then the verb you use shall be POST, because the semantics of PUT imply "create/overwrite" of a resource, and the semantic you are expressing is append.
If you are delivering a representation of a single message to a resource that represents that message alone (ie: you are doing a create of the message resource), then PUT is preferred to POST. The key idea here is that PUT promises that any side effects on the server are idempotent -- the side effect of successfully delivering N > 0 copies of the message are equivalent to the side effect of delivering exactly 1 copy. Using PUT as the verb shares that promise, not just with the client and server, but also with all of the intermediate connectors along the way.
Your idempotent resources can also support POST, and you can document in your API that the messages received are handled idempotently so that clients will understand, but there's no standardized way to inform the other connectors of this fact.
(Example: think about a form post in a browser. The resource at the server knows that the request can be handled idempotently. You can document in the html itself that hitting the button more than once is safe, but you don't have any way to tell the browser that, so the browser throws up a message to the user saying "re-POST might not be safe, are you sure Y/N?")
In summary, you want your choices of HTTP methods to agree with the uniform interface, so that the client, the server, and all of the components acting on the messages in between have a shared understanding of what's going on.

How to design a REST API which requires resource creation and modification to be approved by another party

I have to design REST services for security sensitive resources that require dual control. What is an elegant way to design the REST services that implement dual control?
Dual Control
With dual control I mean that a change only becomes effective if multiple people (e.g. 2) were involved in the change.
For example, I have resource called userProfile. It defines all things a user is allowed to do. If someone wants to change such a profile, it can propose a change to it. This change then has to be verified. The result of this verification is either "Approve" or "Reject". Once a change has been approved it becomes effective.
Design
I currently have a userProfile resource and a userProfileChangeProposal resource.
creating a proposal to create a userprofile happens through
POST /userprofiles
This returns the ID of the userprofile. It can now be verified using that {id}
PUT /userprofiles/{id}/changeproposal
Deleting or updating the userprofile requires a proposal again, so:
DELETE /userprofiles/{id}
PUT /userprofiles/{id}
These changes can be verified again via: (there can only be 1 proposal at the same time for a userprofile)
PUT /userprofiles/{id}/changeproposal
Issues
The thing I'm struggling with is that the rest operations seem to operate on the userprofile resource, but in fact they dont. A delete doesn't directly delete the resource. It creates a proposal to delete it.
Also, this approach doesn't allow direct deletion of a userprofile.
On the other hand, if all changes occur through change proposals, then all create/delete/update actions are just
CREATE /userprofilechangeproposal
I havent seen anything on the internet regarding dual control design. The closest was that someone first creates an ORDER resource and only after the order has been approved the actual CAR is created.
Anyone has any best practices?
I think this post on Rest Cookbook answers your question. The same article, but a little more verbose can be found here and here.
Summarizing the info in the URL your workflow should look like this:
User sends a POST to /userprofiles with the profile info in the payload { "username": "user1298232" } (as an example)
The service replies with 202 Accepted and Location: /proposals/12345 header.
User can check the proposal status by sending a GET /proposals/12345 request. This resource might look like this { "status": "waiting for approval" }
When the actual resource has been accepted and created (e.g. with an id of 1) GET /proposals/12345 no longer returns the status, but instead will redirect (with a 303 response status code and Location header) the request to the newly created resource at /userprofiles/1.
4a. Later on the client can either DELETE the proposal resource or the server can expire it and return a 410 Gone (after some time as an element of garbage collection).
4b. If the proposal gets rejected then its status should change accordingly (e.g. { "status": "Rejected" }).
NOTE (from the article):
Don't use a 301 or 302 when a resource has been created. These codes tell the client that the SAME resource can be found at another location. A 303 tells a client that ANOTHER resource can be found at ANOTHER location.
The same workflow can be used to modify/delete a resource.
EDIT: APPROVING PROPOSALS
I forgot to write how to approve requests. The most natural approach to this would be for the authorized user to send a partial update PATCH /proposals/1 including the status change - { "status": "approved" }.
There is a discussion on how the payload of a PATCH request should look like. The above method of describing a partial update (a partial resource including only the attributes to be updated) is implemented e.g. in the GitHub API which by many is considered the role model of a RESTful API. Presented here is another approach, which would require the payload to describe the change itself instead of the partial resource with the attributes to update: { "op": "replace", "path": "/status", "value": "approved" }.
PATCH is not yet an official HTTP method, so theoretically it may cause some problems in certain environments althought personally I haven't yet encountered such a scenario (comment under this SO post suggests that there might be a problem with PATCH in MS Edge, but I haven't checked that). Anyway you could design /proposals/[id] to accept PUT requests just to be on the safe side. Just remember that PUT should replace the resource and should contain the whole resource in the payload, not only the changed properties.
EDIT 2
Regarding the PATCH problem: it seems that GitHub API actually allows partial updates with POST as well because of the mentioned above possible PATCH incompatibility with some clients. So POST in addition to its normal duties (resource creation) gets the partial update capabilities when given resource ID (link -> section HTTP Verbs):
PATCH - Used for updating resources with partial JSON data. For instance, an Issue resource has title and body attributes. A PATCH request may accept one or more of the attributes to update the resource. PATCH is a relatively new and uncommon HTTP verb, so resource endpoints also accept POST requests.

REST creation without persisting

Right now I have a REST service which creates a report via a POST:
POST http://myhost/reports
The report however is not persisted, and cannot later on be retrieved via a GET:
GET http://myhost/reports/{id}
Instead I return the report immediately in the response to the POST. Am I violating any REST principle here, e.g. anything a POST creates should always be accessible via a GET, or is this setup OK?
The POST method isn't a synonym to the create in CRUD. The POST method is used for any operation that isn't standardized, so as long as you document what it does, you're not violating REST, no matter what you do.
There's no such REST principle saying "anything a POST creates should always be accessible via a GET". This is a common misunderstanding due to conflating REST with CRUD. Read this answer for some clarification on that.
In informal language, what a POST says to the server is "take this data and apply it to the resource identified by the given URI, following the rules you documented for the resource media type."
No, you are not violating REST. As long as your interface is uniform it is up to you to determine what actions the urls of your API perform.
As part of your documentation you simply need to state which methods are valid for certain resources and which aren't. I really like to use the Twitter API as a good example of "What to do"
Example: Twitter REST API
POST statuses/update
does not create an object available for access at
GET statuses/update/3
The action performed by the POST method might not result in a resource
that can be identified by a URI. In this case, either 200 (OK) or 204
(No Content) is the appropriate response status, depending on whether
or not the response includes an entity that describes the result.
So according to the HTTP standard this is okay.

Using SoapUI to test Login function of REST application

I don't make this very general question post lightly, but I've maxed out what I can figure out on my own.
I'm starting up the QA Test Automation at my new company (they don't automate anything currently) and they've elected to use SoapUI for this procedure.
The application they're developing is a REST application (I don't really have any idea what that means) so I'm trying to build a REST request and Test Suite to reach our internal test server (which gets me XML that I am not allowed to post here - but it does reach the server successfully!) and then try to do a Login/Logout test.
I'm asking for help with methodology, because I have no idea where to start. I;ve Googled and trolled their support forums and looked in every corner of YouTube. Everyone is doing something different enough that I can't relate or use it.
Does anybody out there use SoapUI and test functional login in a REST application? I can write HTML/CSS and I'm pretty Java savvy, so I can do technical stuff if I know what to look for and what to learn.
Feeling overwhelmed. This was not in my job description when I started.
You should start with REST, and after that with SoapUI.
It is hard to catch the essence of REST.
It is like the hybrid of SOAP and a simple HTML driven web application. By SOAP you describe your web service with a WSDL. By a web application you send back hypermedia, so you don't have to write a WSDL or any descriptor to your application. This is convention over configuration...
REST uses the same approach, so it sends back hypermedia as well, but it sends not HTML, because it is not machine processable. The hypermedia sent by a REST API is usually an XML or a JSON derivative, for example ATOM+XML, JSON-LD, etc... If your web service does not send back hyperlinks, then it is not a real REST service just a SOAP web service with some REST constraints. There is a big difference. By SOAP you have to know everything about the operation name and the parameters if you want to send a request. If something changes, then your SOAP client breaks immediately. By REST your automated client follows links, checks their link-relation, or the bound linked data and recognizes which link is what it was looking for. So the modification of the link's url is irrelevant in the client, because it follows the vocabulary of the application, for example: hydra is a project which tries to describe these application level semantics in a general way, and tries to bind it to open linked data.
So at first you have to check that you have a real REST API, which follows the HATEOAS principle, or just a REST like SOAP web service. This is very important if you want to write end to end tests against it. By testing REST, you have to follow the links in your tests returned by the web API. By testing REST like SOAP, you have to build the links yourself in your tests... How to build such a link? I am sure you got a description of your REST API, but a link looks usually something like this in a JSON format:
{
rel: "link-relations",
method: "METHOD",
href: "domain/api-root/version/resource-path?map-reduce",
data: {...},
title: "...",
...
}
Ofc. there is some difference by every hypermedia, so you have to check your XML hypermedia type, how it represents links... The link-relations and maybe other attributes bind your data to the semantics of your REST API. The METHOD is always a verb, usually: GET, POST, PUT, PATCH, DELETE, maybe OPTIONS, and so on... There are only a few REST verbs, each of them has a specific meaning. In the url: The domain is the domain name of your application, e.g. https://example.com. The api-root is the root of your REST API, usually /api. The version is the version number of the currently used API, usually /v1. Only non backward compatible vocabulary changes should affect this version number. The resource-path is the path of your resource, usually /users or /users/inf3rno, etc... By REST you have resources. Each of them has a unique resource-path, and as you can see, every word in that path is a noun. So resources are something you can modify or display with a verb. For example a GET /users/inf3rno should return a representation of my profile page, and a PATCH /users/inf3rno {nick: "Leslie"} will turn my nick name: inf3rno into Leslie. By REST every resource should have only a single resource-path, so this is always a unique identifier, therefore the previous example with PATCH was not so perfect if you want to have multiple users with the same nick... The map-reduce in the queryString of the url, and it contains the sorting, pagination and filtering settings of the resource you want to modify or display. For example you can retrieve some data of every user with a first name: "Leslie" with GET /users?filters="firstName: 'Leslie'"&page=3&count=25. There is a difference between the following url-s: /users?id="inf3rno" and /users/inf3rno. The first one points to a collection resource and filters the result by its representation, the second one points to a single item resource. So a GET should return a collection representation with a single item by the first one, and an item representation by the seconds one. By the resource modifying methods there is no difference between the 2 urls... So it is recommended to add only a unique identifier to the resource-path if you want to select an item resource from a collection. By reducing the collection representation in any other ways, you have to add the filters to the queryString. The data part contains the params from the input fields. The title is the title of the link, and so on... You can use url-templates of you want to put input params to the url as well...
By REST the client maintains the session, and it sends the credentials (username, password) with every request. This is because the REST service is like John Snow, it does not know anything about the session or the identity of the user. It has to authenticate every request. To do that it uses a credentials -> permissions cache. This is a good approach, because the service scales very well if it does not have to maintain the session, which is part of the application state (the state of the client)... The REST service maintains only the resource state, which is not dependent on the clients...
The response to your REST requests is usually a hypermedia which contains the links you can follow and the data you requested. By REST like SOAP web services you get only the data in a JSON or XML format. Every response should contain a proper status header. The most frequent status codes are:
200 - ok (by successful PUT, PATCH and GET)
201 - created (by successful POST)
202 - accepted (by async request with eventual consistency)
204 - no content (by successful DELETE)
206 - partial content (by pagination with range headers)
301 - moved permanently (by migration)
304 - not modified (by cache)
400 - bad request (by invalid input)
401 - unauthorized (if no password given, or wrong username or password)
403 - access denied (if your account does not have permission to perform the task)
404 - not found (by unknown resource)
409 - conflict (by concurrency issues or duplicated request or db constraint problems)
410 - gone (if the resource was present before, but it is already deleted)
415 - unsupported media type (if the client wants the response in an unknown media type)
500 - internal server error (if the request was okay, but something went wrong by processing it)
By any error you have to send a detailed error message with a custom error code, which is understandable for the users, not just the developers...
That's how a REST API looks like.
To test it with e2e tests you have to set fixtures send REST requests and check their response. So it is like any other test... The SoapUI is not necessarily the best tool to do that, I read many complaints about it... I personally never used it, but it is not so hard to write your custom testing system. You need a testing framework, which can compare expected and actual values. You need something to send HTTP requests, or simply mock out the HTTP framework of the REST API. You need something for the fixture. By integration tests you can mock out the business logic and the HTTP framework as well, so by those you just inject the mock dependencies and check the calls. By e2e tests you need a test data set, and compare it with the result XML in your case... If you want to e2e test your client, you can use selenium if it is HTML based, maybe with nightwatch.js. By testing a real REST API, you'll need an automated browser, like selenium for your REST API implementation, which can select and follow the proper links. If you are developing the REST API you would write a browser like that anyways if you want an example client for your 3rd party client developers.

Where in a HATEOAS architecture do you specify the HTTP verbs?

I was reading an article on HATEOAS and while I understand the idea of providing the URLs for further actions in the response, I don't see where you specify what HTTP verbs should usedto interact with those URLs.
For example, from What is HATEOAS and why is it important for my REST API?, how from this response
GET /account/12345 HTTP/1.1
HTTP/1.1 200 OK
<?xml version="1.0"?>
<account>
<account_number>12345</account_number>
<balance currency="usd">100.00</balance>
<link rel="deposit" href="/account/12345/deposit" />
<link rel="withdraw" href="/account/12345/withdraw" />
<link rel="transfer" href="/account/12345/transfer" />
<link rel="close" href="/account/12345/close" />
</account
do you know if I should issue an HTTP PUT or POST to /account/12345/close?
Don't puts verbs in your URIs (eg /account/12345/transfer). URIs represent resources, not actions.
The verbs to use are defined by the HTTP protocol (eg GET, POST, PUT, OPTIONS, DELETE etc). REST is a architecture design with a set of constraints, and HTTP is a protocol that adheres to these constraints. HTTP defines a limited set of verbs to transfer the state of a resource from client to server and vice versa. By definition you are constrained to these verbs only.
The client should decide what HTTP verb to use based on what it is trying to do. The server doesn't need to tell it what verbs there are, it already knows based on the HTTP protocol.
If the client needs to know what verbs it can use on a resource it can query the resource using the OPTIONS verb and look at Allow header in the response (assuming the server returns this information, which it should if it is being helpful). Some resources might only accept GET, while others may accept others such as POST and PUT.
Have a look at the HTTP specification to see what verb to use in what context.
To give an example from your original post. Say you have an account resource with a URI at
/accounts/12345
and you want to close the account. Remember REST is state transfer. The client is closing the account so it has the account in a state of closed on its end. It then transfers that state to the server so that the client and server both are in line with each other. So you PUT the clients state (which is the resource in a closed state) onto the server
PUT /accounts/12345
The body of the request should contain a representation of the resource in a closed state. Assuming you are using XML to represent the account resource it would be something like this
PUT /accounts/12345
<?xml version="1.0"?>
<account>
<account_number>12345</account_number>
<balance currency="usd">100.00</balance>
<state>closed</state>
</account>
The resource on the server now mirrors the resource on the client. Both are in a closed state. If you don't want to transfer the whole resource every time you make a change to one of its attributes you could split them out into a resource hierarchy. Make the status of the account its own resource and PUT to that to change it
PUT /accounts/12345/status
<?xml version="1.0"?>
<state>closed</state>
Your question has a lot of answers on Stackoverlow, but most of them skirt the reason you are asking, and I suspect you always find them partially disatisfying.
If we take Roy Fielding at his word, it is impossible to write most commercial interactive Client-apps as SOA RESTful/HATEOAS using HTTP/HTML. It might be possible in other mediums, I can't say.
So the practical answer is "look it up in the documentation" and "write your Client with that app-knowledge in it" with a side-helping of "ignore the fact that we're breaking Fielding's rules by doing that".
I tend to design JSON responses that provide this approach:
GET /account/12345 HTTP/1.1
{
"account": {
"number": "12345",
"currency": "usd",
"balance": "100.00",
"deposit": {
"href": "/account/12345/deposit",
"action": "POST"
},
"withdraw": {
"href": "/account/12345/withdraw",
"action": "POST"
},
"transfer": {
"href": "/account/12345/transfer",
"action": "POST"
},
"close": {
"href": "/account/12345/close",
"action": "DELETE"
}
}
}
... adding additional properties to the design as needed, but these are the basics.
I believe this allows the consuming Client(s) to be written in a RESTful way, but in so doing I am using the Response Body, which Fielding says is not what he intended.
I'd offer this explanation seperate to the answer though:
Fielding says "I am getting frustrated by the number of people calling any HTTP-based interface a REST API." (http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven).
Note how he so stridently says "any" HTTP-based interface.
The most relevant segment in his 'lecture' is this:
"A REST API should be entered with no prior knowledge beyond the initial URI (bookmark) and set of standardized media types that are appropriate for the intended audience (i.e., expected to be understood by any client that might use the API). From that point on, all application state transitions must be driven by client selection of server-provided choices that are present in the received representations or implied by the user’s manipulation of those representations. The transitions may be determined (or limited by) the client’s knowledge of media types and resource communication mechanisms, both of which may be improved on-the-fly (e.g., code-on-demand). [Failure here implies that out-of-band information is driving interaction instead of hypertext.]"
He says this because an HTTP/HTML app URI media-type is just "text/html", and where is the Verb in that? There isn't one. A URI cannot tell you what Verb something requires for use/navigation, ergo you cannot use just the in-band data alone to construct the 'next' navigation dynamically in your Client.
He explained that he believes we render our URI's as part of CDATA that includes the "method" or that the context of the URI would self-evidently provide it, like the FORM element does. He explicitly rails against the OpenSocialst REST API stating that it is not RESTful.
Here: “anchor elements with an href attribute create a hypertext link that, when selected, invokes a retrieval request (GET) on the URI corresponding to the CDATA-encoded href attribute.” Identifiers, methods, and media types are orthogonal concerns — methods are not given meaning by the media type. Instead, the media type tells the client either what method to use (e.g., anchor implies GET) or how to determine the method to use (e.g., form element says to look in method attribute). The client should already know what the methods mean (they are universal) and how to dereference a URI.
Note that he says the Client should already know what the methods mean, he does not say that the Client should already know what they are - which is why you asked your question. A lot of people struggle with this, because we don't in fact build our apps like this in most SOA environments.
Like a lot of engineers, I just wish Fielding would come out with a clarification or re-statement, but not only has he not done so, he has published two further admonishments to us as engineers, doubling-down on his statement, saying that we should stop calling our API's RESTful and accept that we're building RPC's.
I think the JSON elements-like approach is a reasoble bridge, but I have no answer to the fact that we're using the Request Body to do it, not relying on the Media Type to imply it.
Finally, there is a newer Verb in HTTP called OPTIONS which, for a given URI, would return the allowed Verb actions list. I think Fielding had a hand in writing this HTTP revision. That would allow a Client to generically construct URI navigations without the forbidden internal app knowledge. But that has three issues I can think of in the practical world:
You would have to code a mechanism into your Service Aggregation to make that call for every URI you try to return, and since much data contains many URI's (_links in HAL) that adds a lot of extra 'hops' into your Service Response construction. We'd probably all complain about that.
Virtually no SOA site claiming to be RESTful actually implements an OPTIONS verb-method-call for you to do this enquiry with anyway.
We would all complain about the 'unecessary' extra calls it adds (especially in the eCommerce world) to a Client's processing and its tendency to push us beyond SLA requirements.
do you know if you should PUT or POST to /account/12345/close?
You consult the documentation for the API, that's how you know. HATEOS is not a replacement for formal documentation. Documentation is necessary for REST APIs just like any other API.
HATEOS lets you know what your other options are from a specific resource. It doesn't tell you why you would use those options, or what information you would send them. Content Types only express syntax and high level semantics, not application level semantics, so they're not documentation either.
If you want to know how to use a REST API, read the documentation. If you want someone else to use your REST API, provide them with documentation.
There's no magic here.
#Cormac Mulhall's answer is very good, but I'd like to suggest a refinement that I heard from a colleague:
Actions or events that happen to a resource can be treated as subordinate domain nouns, using the gerund form of the action verb or the event name, but should be placed under a meaningful path identifier such as "actions" or "events" or something similar. The resource representation that will be returned expresses state data about the action, so that POST or PUT operates as a request.
Suppose that orders have several lifecycle states. At some point after being drafted, an order is placed, fulfilled, or cancelled.
Information about these order actions would be located by putting the action name in plural noun form under the resource path with /actions to return details if the actions state is active, or 404 NOT FOUND otherwise.
https://order.api.foobar.com/v1.0/orders/{orderId}/actions/placements
https://order.api.foobar.com/v1.0/orders/{orderId}/actions/fulfillments
https://order.api.foobar.com/v1.0/orders/{orderId}/actions/cancellations
When these actions are idempotent (an order cannot be placed twice in a row), so these actions can be requested by PUT’ing of the appropriate representation to these URIs. When they are not idempotent, the are created by POST’ing to the plural form.
For example, to track approvals order, we could POST to:
https://order.api.foobar.com/v1.0/orders/{orderId}/approvals
and then we see information about individual approvals by doing a GET against:
https://order.api.foobar.com/v1.0/orders/{orderId}/approval/1
It is often useful to use an aggregate called something like "actions" to find all actions:
https://order.api.foobar.com/v1.0/orders/{orderId}/actions
We could POST to this, letting the representation declare what type of action is meant.
You can also get a list of actions across individual orders by leaving the {orderId} parameter off:
https://order.api.foobar.com/v1.0/orders/actions/placements
https://order.api.foobar.com/v1.0/orders/actions
These can be searched by adding query parameters:
https://order.api.foobar.com/v1.0/orders/actions/placements?since={sinceTimestamp}