I'm writing a RESTful HATEOAS API. I have compound entities which I have to GET, POST and PUT. The GET part is easy, and has lots of examples. The response contains the entity's primitive attributes, and links to nested entities. For example:
{
"id":"2",
"firstName":"Brad",
"lastName":"Pitt",
"balance":1234.5,
"transactions":"http://localhost:8080/jersey-poc/api/v1.1/account/1/transactions",
"self":"http://localhost:8080/api/v1.1/account/1",
"accountType":"http://localhost:8080/api/v1.1/account/1/accountType"
}
The problem arises when I want to create or modify the account. I need to associate the account with an accountType. I can send the a POST request such as the following: {"firstName":"Michael","lastName":"Jackson","balance":300.0,"accountTypeId":5}
but that would break the HATEOAS paradigm. What is the best practice to POST/PUT compound entities?
There's nothing particular about that payload that would go against HATEOAS; the only real problem is that the accountTypeId
isn't very discoverable. (Magic IDs are always better off being mapped into short descriptive strings; think of them as being like an enumeration.) One of the key things to remember when working to a HATEOAS model is that the entity that the user POSTs does not need to be exactly the entity that creates the resource; you can modify it, annotate it, translate it. It should still be conceptually the same, but that's totally different to being identical. (Adding IDs and creation timestamps would be excellent examples of how extending would be totally reasonable.)
To me it sounds like your real problem is that you need to reconsider just what information clients should submit when doing a POST, and how you intend to tell clients that they should submit that information when doing the POST. Myself, I quite like using XML for upload here, because I can easily tell clients that their POST payloads should conform to a particular schema (and both XML Schema and RELAX NG are rich enough for me to describe the constraints). I'm sure that's not the only way to do it.