How do I describe POST links in HAL?
I'm designing a RESTful API with HATEOAS constraints, similar to Wikipedia's HATEOAS example but expressed in HAL JSON (dropping the scheme, host, etc. for clarity):
GET /accounts/12345
{
"id" : 12345,
"balance" : 100.00
"_links" : {
"self" : {
"href" : "/accounts/12345"
},
"transfer" : {
"href" : "/accounts/12345/transfer{?amount,target}",
"templated" : true
}
}
}
To perform the "transfer" action, the client would presumably do:
GET /accounts/12345/transfer?amount=100.00,target=54321
{
"id" : 34567,
"amount" : 100.00
"_links" : {
"self" : {
"href" : "/transfers/34567"
},
"source" : {
"href" : "/account/12345"
},
"target" : {
"href" : "/account/54321"
}
}
}
Invoking the "transfer" link via GET creates a new ressource in "transfers". But doing a GET to create a new resource is not idempotent and it "feels" wrong; a RESTful resource centric API would POST:
POST {amount: 10.00, source: 12345, target: 54321} /transfers/
{
"id" : 34567,
"amount" : 100.00
"_links" : {
"self" : {
"href" : "/transfers/34567"
},
"source" : {
"href" : "/account/12345"
},
"target" : {
"href" : "/account/54321"
}
}
}
But how do I describe this POST and the required form elements in HAL so the client can just do the "Right Thing" without being hard-coded? Perhaps something like:
{
"id" : 12345,
"balance" : 100.00
"_links" : {
"self" : {
"href" : "/accounts/12345"
},
"transfer" : {
"href" : "/transfers{?amount,source,target}",
"templated" : true,
"method" : "POST"
}
}
}
But method
not part of the HAL specification and there's no analogous identifier -- so it feels like I'm on the wrong track...
Perhaps my client should just "know" that a GET of transfer
returns matching transfer resources, and a POST to transfer
creates a new transfer resource.
FWIW, my implementation uses Spring Boot 2 with Spring HATEOAS so the follow-up question is how to express this with Spring HATEOAS...
You can't do that with HAL. Mike Kelly, the creator of HAL, states on GitHub
The "HAL way" of doing this is to use the link rel documentation to convey the available methods in a human readable form. ie. your barks example would look like this (notice the "barks" link rel is now a URL)
{ "_links": { "http://docs.example.com/barks": { "href": "/v1/dogs/1/barks" } } }
and if a developer fetches the URL http://docs.example.com/barks in a browser, the documentation can specify the available methods, valid request bodies, potential response codes, response bodies, etc. The developer will then codify this into the client she is building.
This is a major flaw of the HAL spec imho, but there are other mediatypes that tackle this issue, like Mason or the HAL extension HAL-FORMS. It might be worth checking these out, though I'm not sure how they integrate with Spring.