Stimmler
Stimmler

Reputation: 462

RESTful API endpoints for managing states

I have a REST API and want to implement different states for some resources. The API is at the Level 2 of the Richardson Maturity Model.

I've seen a lot of different approaches regarding the endpoints for changing the states, but I'm not sure what's the recommended one.

My scenario is the following: My entities are orders. An order can be open, closed and in progress.

  1. I could make a PATCH request to /orders/{id} with the request body
{
 "state": "in-progress"
}
  1. I could add an action parameter to the endpoint /orders/{id}/status/in-progress and make a POST request to trigger that action. But that would have a smell of RPC.
  2. I could treat the state as a resource and make a PUT request to update it. /orders/{id}/state
{
  "state": "in-progress"
}

In addition to that, I'm not sure what should be in the response body.

  1. The response could only be 202 Accepted without body.
  2. Or a 200 Ok with the updated state as body.
{
  "state": "in-progress"
}
  1. Or a 200 Ok with the order and it's updated state as body.
{
  "id": 1
  "state": "in-progress"
}
  1. Or a 200 Ok with the order and it's updated state + the next possible states as body. This feels like a small step towards Hypermedia / Maturity Level 3.
{
  "id": 1
  "state": "in-progress"
  "nextStates": ["closed"]
}

There are a lot of opportunities. It seems like that I can't model the endpoints like resources, how it's should be done for RESTful APIs. But I also don't want to use actions like in RPC. And I know it's only REST if you have Hypermedia but that's to complex and pricey to implement.

Upvotes: 0

Views: 1243

Answers (1)

VoiceOfUnreason
VoiceOfUnreason

Reputation: 57299

The basic idea: resources are abstractions of documents. A client sends information to the server by requesting modifications to documents. Useful business activity is a side effect triggered by the modifications to the documents.

So if your client want to tell the server about the state of an order, then the idea is to find the document with the state information, and to send a message requesting that document be modified.

On the web, we do this by submitting forms - little messages describing the change we want to make to the document. That might look like

POST /orders/12345
Content-Type: application/x-www-form-urlencoded

action=changeState&state=in-progress

Another alternative is to edit the document locally, and then send the server a copy of the edited document

PUT /orders/12345
Content-Type: application/json

{
    "id": "12345",
    "items": [
       "loaf of bread",
       "container of milk",
       "stick of butter"
    ],
    "state": "in-progress"
}

The schema here is the same that was provided to us by "GET /orders/12345", we're sending the entire document back to the server, including our changes.

When the document is very large (relative to the HTTP headers), and the change is small, then we might instead prefer to send a patch document that describes the changes. For example

PATH /orders/12345
Content-Type: application/json-patch+json

[ {"op":"replace", "path":"/state", "value":"in-progress"} ]

It's the same idea as with PUT: we've made changes to our copy of the document, and we ask that the server changes its copy of the document to match ours.


In addition to that, I'm not sure what should be in the response body.

200 OK, with either

  • a representation of the status of the action (aka a success message)
  • an updated representation of the resource

The metadata (in particular, the Content-Location header) tells the client which is which.

Upvotes: 0

Related Questions