Resource Sets
Many resources may be in one of n discrete states. The state of the
resource is often represented by a string property named state
.
Changing states differs from updating other properties which are
typically done with PUT
or PATCH
, because such transitions are
guarded by business rules which the service enforces. For example, in
the Transfers API, you can’t cancel a scheduled transfer which is
currently being processed by the bank (its too late!), nor can you
resume a transfer which is not suspended. To enable (and enforce) this
in a clean API manner, Apiture Digital Banking APIs perform state transitions with
operations that place a resource into one of n discrete resource
sets. The resource set represents (abstractly) a set of all resources
that are in a specific state.
After creating a scheduled transfer, the user may want to
suspend the recurrence, resume a suspended recurring transfer, or
cancel it. Rather than requiring the user to PATCH
the resource
(which can update many other fields), the state
property is
immutable via PATCH
or PUT
. To change the state of the transfer,
use one of the links in the transfer resource. A scheduled transfer
response may contain the following links in its HAL response:
{
"_id" : "3d28fb7c-16e9-4ee5-bd37-37971bbe5e46",
"_profile" : "http://api.apiture.com/schemas/transfers/scheduledTransfer/v1.0.0/profile.json",
"amount": {
"value": "345.50",
"currency": "USD"
},
"description": "Car payment",
"state": "recurring",
"schedule": {
"start": "2018-02-05",
"count": 3,
"every": "P1M",
"end": "2021-04-05"
},
"..." : "... other properties ...",
"_links" : {
"self" : { "href" : "/transfers/scheduledTransfers/3d28fb7c-16e9-4ee5-bd37-37971bbe5e46" },
"apiture:suspendScheduledTransfer" : {
"href" : "https://api.thirdpartybank.com/transfers/suspendedScheduledTransfers?scheduledTransfer=3d28fb7c-16e9-4ee5-bd37-37971bbe5e46"
},
"apiture:resumeScheduledTransfer" : {
"href" : "https://api.thirdpartybank.com/transfers/resumedScheduledTransfers?scheduledTransfer=3d28fb7c-16e9-4ee5-bd37-37971bbe5e46"
},
"apiture:cancelScheduledTransfer" : {
"href" : "https://api.thirdpartybank.com/transfers/canceledScheduledTransfers?scheduledTransfer=3d28fb7c-16e9-4ee5-bd37-37971bbe5e46"
}
}
This is Hypermedia in action!
These links are implemented by a POST
to resource set URIs,
passing the ID or URI of the current transfer as a query parameter.
The complexity is hidden behind the link, but inspecting
the OpenAPI definition and the links at runtime would show that one honors the link with a POST operation,
such as the following:
POST https://api.thirdpartybank.com/transfers/suspendedScheduledTransfers?scheduledTransfer=3d28fb7c-16e9-4ee5-bd37-37971bbe5e46
The API can enable these links if and only if the state transition is
allowed: if a transfer is in a processing state, the
apiture:suspendScheduledTransfer
link is not available in the set of
links within the transfer’s JSON representation. Also, the client
cannot change the state
at all from scheduled
to processing
or
from processing
to failed
because those state transitions are
managed by the service only. Thus, there is no link or operation to
put the transfer into the processing
resource set or into the
completed
resource set.
Note that other links and state transitions can be added in the
future. Also, permissions limit who can execute those
links/operations. The user can suspend their scheduled transfers.
Only the service can execute the transition to processing
and
actually execute the transfer of funds in the back end, or set the
terminal state to failed
or completed
.
This pattern follows the uniform interface constraint of REST APIs:
the URIs are addresses of resources (in this case, resource sets), and
the APIs use POST
to perform the operation of placing a resource
into that resource set.