API: Actions - QutEcoacoustics/baw-server GitHub Wiki
Specialized actions:
- Should be avoided as RPC is a REST anti-pattern
- Be avoided when there are significantly different result payloads returned. This may indicate a design better represented as a nested resource
Actions are good choice for manipulating a state machine. They should also significantly improve our OpenAPI documentation.
If absolutely needed an action should be exposed:
- SHOULD take the form of
POST /resource/{verb}
- it is nested under a resource (e.g.
/analysis_jobs/1/suspend
) - it is nested a under a single resource, not a list or filter endpoint
- e.g. NOT
/analysis_jobs/
- e.g. NOT
- it is nested under a resource (e.g.
- MUST NOT be invokable with a
GET
request - the GET verb is idempotent, it should not affect state - SHOULD be invoked with a
POST
verb- however,
PUT
is acceptable but unlikely to be relevantPUT
indicates the replacement of a state and should be idempotent- It is unlikely you need an action (that has a side effect) which is also idempotent
- however,
DELETE
is also acceptable if the semantics are correct
- however,
- The invocation MUST have a side effect
- May accept a body with parameters
- But if a lot of parameters are needed then this is a code smell: perhaps you should reconsider the design of your resource?
- We don't currently have any example of actions accepting parameters. If we find such cases, we need to reconsider this guidance.
- May return a body with information about the action
- We don't currently have any example of actions returning a body. If we find such cases, we need to reconsider this guidance.
- Should return
204 No Content
- We set a
Location
header for a successful response but this is technically not in spec. - The resource should return cache headers that reflect that caching is not allowed
- It must NOT return the resource
- e.g.
analysis_jobs/1/suspend
should not return/analysis_jobs/1
- We have a
GET
request on the resource itself for that
- e.g.
Examples
Invoke an action
POST /analysis_jobs/1/retry
204 No Content
Location: /analysis_jobs/1
Cache-Control: no-cache
An invalid action response
POST /analysis_jobs/2/complete
404 Not Found
X-Error-Type: Custom Errors/Invalid Action Error
Content-Type: application/json; charset=utf-8
Cache-Control: no-cache
{
"meta": {
"status": 404,
"message": "Not Found",
"error": {
"details": "Invalid action: unknown action: `complete`",
"links": {
"retry": "/analysis_jobs/2/retry",
"resume": "/analysis_jobs/2/resume",
"suspend": "/analysis_jobs/2/suspend",
"amend": "/analysis_jobs/2/amend"
},
"info": {
"allowed_actions": [
"retry",
"resume",
"suspend",
"amend"
]
}
}
},
"data": null
}
Historical notes
We have various models which are modeled as state machines.
We would previously allow state transitions by PATCH
ing the state-machine's backing field. e.g. PATCH harvests/123
with a body of {"harvest:{"status":"scanning"}}
. This worked but it introduces a few problems:
- given a desired state, we had to infer which event (transition) method to call
- this requires flat state machines - i.e. only one transition (path) possible between states
- which in turn, requires more states in the machine, which exponentially increases the number of possible cases.
- it also makes it awkward to affect more than one state machine on a resource
- and the naming is awkward
- rather than execute a verb that shows intent (e.g.
POST harvests/123/scan
) - we sent an adjective like
scanning
- rather than execute a verb that shows intent (e.g.
Most of our state machines still follow the PATCH strategy. This behaviour should be considered deprecated and URL actions as described in this document should be implemented at an opportune time.