0

How to best extend REST with FSM state changes?

No one can know if a state change is idempodent or not, so the wisest thing may be to assume they're not, and as a general rule use POST, ok?

To me and my findings, POST makes more sense than PUT or PATCH.

POST /coffeemachines/{id}/start

or maybe more verbose?

POST /coffeemachines/{id}/state/start

Although start looks like a verb (breaking REST-practices), I think it's not:

  • The main verb is a poking POST, we want a state-change.
  • start is just the attribute-value for the requested state-change.

I guess I'm not the first man on the moon here, thankful for any references or thoughts.

Teson
  • 6,644
  • 8
  • 46
  • 69
  • You may find this useful - https://stackoverflow.com/questions/17529315/hateoas-how-to-model-link-relations-that-change-state – Mo A Jan 16 '19 at 11:07

2 Answers2

2

You can send a partial update request with HTTP PATCH that contains only the new state.

PATCH /coffeemachines/{id}
{
    status: "active"
}

According to Wikipedia:

The PATCH method is a request method supported by the HTTP protocol for making partial changes to an existing resource. The PATCH method provides an entity containing a list of changes to be applied to the resource requested using the HTTP URI. The list of changes are supplied in the form of a PATCH document.

It is also more readable to separate words in the path with hyphens. For example:

PATCH /coffee-machines/{id}
{
    status: "active"
}
scokmen
  • 571
  • 3
  • 19
  • I've considered this too, but discarded patch for reasons I don't remember.. The state-change could be considered as something "new" as in POST /statechange but the PATCH-approach clearly makes more sense when in a resource-context. – Teson Jan 16 '19 at 13:32
  • @scokmen I have seen this suggestion in other places as well, and it makes sense because using actions in URIs is not considered REST. But REST API should be discoverable and implement HATEOAS. How can a consumer know what possible state changes are available? Also, letting the consumer to give you the name of the next state might be a security risk. If you have separate endpoints like OP mentioned, then you can list all available next states as HATEOAS links and make the API more discoverable. So in my mind, both options have trade offs and I have yet to find a fully RESTful solution to this – V. Samma Apr 02 '23 at 17:27
2

REST verb for state change - can we agree on POST?

The reference implementation of REST is the World Wide Web, which was catastrophically successful even though HTML (the dominant media type) only specified support for GET and POST.

Using POST for unsafe operations is fine.

Although start looks like a verb (breaking REST-practices)

No -- REST doesn't care about the spellings of URI. That's part of the point: the server can change the URI in links any time it likes because the clients just follow the links.

That said, there is an issue with your proposed identifiers, which you may want to consider

/coffeemachines/{id}
/coffeemachines/{id}/start

As far as REST is concerned, these are different resources. That means that your locally cached copy of /coffeemachines/{id} is not invalidated when you POST a request to /coffeemachines/{id}/start.

If you care to take advantage of the caching support that is already built into the domain agnostic components that are available, then you want the target of the POST to match the target of the GET: /coffeemachines/{id}

/coffeemachines/{id}/start, in this design, isn't the target of the POST, but is instead the identifier of the form resource that submits start messages to /coffeemachines/{id}. Likewise, /coffeemachines/{id}/stop would identify the form resource that submits stop messages.

The representation of the coffee machine would include links to these forms when the transitions are permitted; for instance, when the coffee machine is off, then the representation of the coffee machine returned by GET would include a link to the start form, but not a link to the stop form.

/coffeemachines/{id}/start and /coffeemachines/{id}/stop are different resources from /coffeemachines/{id}, and therefore might have their own caching policies.

Of course, it isn't required that the forms be separate resources -- the mechanism would also work if the forms were part of the representation of the /coffeemachines/{id} resource itself.

Can I ask you to elaborate around POST vs PATCH

I found that this observation by Roy Fielding helped me:

HTTP does not attempt to require the results of a GET to be safe. What it does is require that the semantics of the operation be safe, and therefore it is a fault of the implementation, not the interface or the user of that interface, if anything happens as a result that causes loss of property

PATCH has stricter semantics than POST; that means that clients (and generic components) can make stronger assumptions about what is going on.

So in the following examples:

PATCH /foo HTTP/1.1
Content-Type: application/json-patch+json

POST /foo HTTP/1.1
Content-Type: application/json-patch+json

The server can handle these messages in exactly the same way. Clients that recognize the PATCH method will recognize that the unsafe changes on the server are supposed to be all-or-nothing ("The server MUST apply the entire set of changes atomically...") and can leverage that as they like, but with POST, that additional constraint is missing and cannot be assumed.

The PATCH spec notes:

A comparison to POST is even more difficult, because POST is used in widely varying ways and can encompass PUT and PATCH-like operations if the server chooses. If the operation does not modify the resource identified by the Request-URI in a predictable way, POST should be considered instead of PATCH or PUT.

Community
  • 1
  • 1
VoiceOfUnreason
  • 52,766
  • 5
  • 49
  • 91
  • Can I ask you to elaborate around POST vs PATCH because I'm still confused about any formal rules here. Example, https://apihandyman.io/do-you-really-know-why-you-prefer-rest-over-rpc/ both POST and PATCH fits for a state-change which makes no sense to me. – Teson Jan 19 '19 at 12:03
  • I don't believe that article by Arnaud Lauret is particularly effective. If you already "get it", then you can find the right meanings in what he wrote. If you don't, then I don't believe it helps at all. – VoiceOfUnreason Jan 19 '19 at 13:43