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?
The first REST API request in a session must be a sign-in request. This is a POST request that sends the user credentials in the body of the request. Because this is a POST request, the request must include the Content-Type header. You can send your the body of the request block as XML or JSON.
The HTTP verbs comprise a major portion of our “uniform interface” constraint and provide us the action counterpart to the noun-based resource. The primary or most-commonly-used HTTP verbs (or methods, as they are properly called) are POST, GET, PUT, PATCH, and DELETE.
To post JSON to a REST API endpoint, you must send an HTTP POST request to the REST API server and provide JSON data in the body of the POST message. You also need to specify the data type in the body of the POST message using the Content-Type: application/json request header.
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.
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