REST API#
This package extends two endpoints of plone.restapi. Both additions are additive: every key those endpoints already returned is returned unchanged, with the same value.
The additions apply to participating content only. Content that provides no participating behavior is served exactly the payload core produces, as shown under Content without additional workflows.
See also
The endpoints these extend are documented in the Plone REST API reference, under Workflow and History.
GET @workflow#
Returns the workflow information for a content object.
http
GET /plone/member-profile/@workflow HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
curl
curl -i -X GET http://nohost/plone/member-profile/@workflow -H "Accept: application/json" --user admin:secret
httpie
http http://nohost/plone/member-profile/@workflow Accept:application/json -a admin:secret
python-requests
requests.get('http://nohost/plone/member-profile/@workflow', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))
HTTP/1.1 200 OK
Content-Type: application/json
{
"@id": "http://localhost:55001/plone/member-profile/@workflow",
"chain": [
{
"history": [
{
"action": null,
"actor": "admin",
"comments": "",
"review_state": "private",
"time": "1995-07-31T17:30:00+00:00"
}
],
"state": {
"id": "private",
"title": "Private"
},
"state_variable": "review_state",
"title": "Simple Publication Workflow",
"transitions": [
{
"@id": "http://localhost:55001/plone/member-profile/@workflow/publish",
"title": "Publish"
},
{
"@id": "http://localhost:55001/plone/member-profile/@workflow/submit",
"title": "Submit for publication"
}
],
"workflow_id": "simple_publication_workflow"
},
{
"history": [
{
"action": null,
"actor": "admin",
"comments": "",
"time": "1995-07-31T17:30:00+00:00",
"workflow_states": "pending"
}
],
"state": {
"id": "pending",
"title": "Pending"
},
"state_variable": "workflow_states",
"title": "Membership",
"transitions": [
{
"@id": "http://localhost:55001/plone/member-profile/@workflow/activate",
"title": "Activate"
}
],
"workflow_id": "foundation_member_workflow"
}
],
"history": [
{
"action": null,
"actor": "admin",
"comments": "",
"review_state": "private",
"time": "1995-07-31T17:30:00+00:00",
"title": "Private"
}
],
"state": {
"id": "private",
"title": "Private"
},
"transitions": [
{
"@id": "http://localhost:55001/plone/member-profile/@workflow/publish",
"title": "Publish"
},
{
"@id": "http://localhost:55001/plone/member-profile/@workflow/submit",
"title": "Submit for publication"
}
]
}
The chain key#
chain holds one entry per workflow applying to the object, in chain order.
The first entry is always the workflow configured for the content type—the one driving review_state.
Contributed workflows follow, in the order their behaviors contribute them.
Each entry holds the following keys.
workflow_idId of the workflow, as
portal_workflowregisters it.titleThe workflow's own title, translated.
state_variableThe variable this workflow drives.
review_statefor the primary workflow; neverreview_statefor an additional one.stateThe object's current state in this workflow, as an object with
idand a translatedtitle. The title comes from the workflow's own state definition, so it resolves for a contributed workflow that the content type's configured chain does not mention.transitionsThe transitions of this workflow available to the current user, each with an
@idtoPOSTto and a translatedtitle. A transition id defined by more than one workflow in the chain is attributed to the first workflow that defines it, which is howdoActionForresolves the same collision.historyThis workflow's own
review_historyentries. A workflow that records no history reports an empty list.
The top-level transitions key#
For participating content, the top-level transitions list is narrowed to the primary workflow's transitions.
This is deliberate.
A client written before this package existed reads that list and offers its contents as publication actions; widening it would make an unrelated workflow's transitions appear in a publication menu.
Every transition remains available under chain, grouped by the workflow that owns it.
Content without additional workflows#
A content object providing no participating behavior is served core's payload, with no chain key.
http
GET /plone/plain-doc/@workflow HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
curl
curl -i -X GET http://nohost/plone/plain-doc/@workflow -H "Accept: application/json" --user admin:secret
httpie
http http://nohost/plone/plain-doc/@workflow Accept:application/json -a admin:secret
python-requests
requests.get('http://nohost/plone/plain-doc/@workflow', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))
HTTP/1.1 200 OK
Content-Type: application/json
{
"@id": "http://localhost:55001/plone/plain-doc/@workflow",
"history": [
{
"action": null,
"actor": "admin",
"comments": "",
"review_state": "private",
"time": "1995-07-31T17:30:00+00:00",
"title": "Private"
}
],
"state": {
"id": "private",
"title": "Private"
},
"transitions": [
{
"@id": "http://localhost:55001/plone/plain-doc/@workflow/publish",
"title": "Publish"
},
{
"@id": "http://localhost:55001/plone/plain-doc/@workflow/submit",
"title": "Submit for publication"
}
]
}
Important
Test for the presence of the chain key rather than assuming it.
A client that reads chain unconditionally breaks on the first non-participating object it meets.
POST @workflow/{transition}#
Executes a transition.
This endpoint is core's, unchanged: a transition belonging to an additional workflow is executed exactly like a publication transition, using the @id reported for it under chain.
http
POST /plone/member-profile/@workflow/activate HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
curl
curl -i -X POST http://nohost/plone/member-profile/@workflow/activate -H "Accept: application/json" --user admin:secret
httpie
http POST http://nohost/plone/member-profile/@workflow/activate Accept:application/json -a admin:secret
python-requests
requests.post('http://nohost/plone/member-profile/@workflow/activate', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))
HTTP/1.1 200 OK
Content-Type: application/json
{
"action": null,
"actor": "admin",
"comments": "",
"review_state": "private",
"time": "1995-07-31T17:30:00+00:00",
"title": "Private"
}
The response reports review_state, as it always has.
A transition belonging to an additional workflow does not change it—read the new state from chain with a follow-up GET, or from the @workflow expansion of the object.
GET @history#
Returns the history of every workflow in the chain, merged into one stream, newest first.
http
GET /plone/member-profile/@history HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
curl
curl -i -X GET http://nohost/plone/member-profile/@history -H "Accept: application/json" --user admin:secret
httpie
http http://nohost/plone/member-profile/@history Accept:application/json -a admin:secret
python-requests
requests.get('http://nohost/plone/member-profile/@history', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"action": "activate",
"actor": {
"@id": "http://localhost:55001/plone/@users/admin",
"fullname": "admin",
"id": "admin",
"username": null
},
"comments": "",
"state_title": "Active",
"time": "1995-07-31T17:30:00+00:00",
"transition_title": "Activate",
"type": "workflow",
"workflow_id": "foundation_member_workflow",
"workflow_states": "active"
},
{
"@id": "http://localhost:55001/plone/member-profile/@history/0",
"action": "Edited",
"actor": {
"@id": "http://localhost:55001/plone/@users/admin",
"fullname": "admin",
"id": "admin",
"username": null
},
"comments": "Initial version",
"may_revert": true,
"time": "1995-07-31T18:30:00+00:00",
"transition_title": "Edited",
"type": "versioning",
"version": 0,
"workflow_id": null
},
{
"action": "Create",
"actor": {
"@id": "http://localhost:55001/plone/@users/admin",
"fullname": "admin",
"id": "admin",
"username": null
},
"comments": "",
"state_title": "Pending",
"time": "1995-07-31T19:30:00+00:00",
"transition_title": "Create",
"type": "workflow",
"workflow_id": "foundation_member_workflow",
"workflow_states": "pending"
},
{
"action": "Create",
"actor": {
"@id": "http://localhost:55001/plone/@users/admin",
"fullname": "admin",
"id": "admin",
"username": null
},
"comments": "",
"review_state": "private",
"state_title": "Private",
"time": "1995-07-31T20:30:00+00:00",
"transition_title": "Create",
"type": "workflow",
"workflow_id": "simple_publication_workflow"
}
]
The workflow_id key#
Every entry carries a workflow_id, including the ones core produces.
For a workflow entry, it is the id of the workflow that recorded the transition.
For a versioning entry, it is
null. Such an entry belongs to no workflow.
The key is present on every entry, so a client may read it without a guard.
Entries are otherwise shaped exactly as core shapes them, and carry the same keys.
A workflow entry also carries its own workflow's state variable: review_state for the primary workflow, and whatever variable an additional workflow declares.
Note
Each workflow's review_history is read separately, so each workflow's own info guard decides whether its entries are visible to the current user.
An entry the guard hides is absent rather than redacted.
Compatibility#
Payload |
Before |
After |
|---|---|---|
|
core's payload |
unchanged |
|
core's values |
unchanged |
|
every transition the chain offered |
narrowed to the primary workflow |
|
core's shape |
one key added, |
|
core's behavior |
unchanged |
The examples on this page are generated by the test suite, in backend/tests/docs/, and are regenerated on every run.
A payload that changes shape without the documentation changing with it fails the suite.