Customisations
A powerful feature of the On Key REST API, is the ability for consumers of the API to define their own customisations for most of the existing On Key API endpoints (known as Resource Actions). Resource Action customisations allows consumers of the API to be very specific about the information they send to or receive from the On Key server.
For example, if you are only interested in a small subset of information returned by a Resource Action, you can create a customisation to return a smaller subset compared to the default system provided implementation of the same Resource Action.
The same ability to limit, filter, sort and parameterise data using the OKQL is also supported by Resource Action customisations. Instead of having to provide these values as query string parameters with every call, they are stored as part of the Resource Action customisation. Consumers can call these customisations by simply appending ?cid={customisationId}
to the existing Resource Action endpoint. This allows customisations to be created and managed centrally by a group of domain experts but still allow all users to execute the endpoints without having to remember what OKQL fragments to add as part of their API calls.
To understand the scope of what Resource Actions and properties are available for customisation, it is important to first understand the metadata endpoints that are available to inspect the existing On Key Resource Actions.
Metadata Endpoints
The On Key REST API provides a rich set of metadata endpoints as part of the System Documents API service grouping. The metadata exposed by these endpoints include information on all the Resources and their respective Resource Actions.
Resource Metadata
To find out what Resource Actions are available for a Resource, inspect the metadata for the Resource as illustrated in the following request for a WorkOrder
Resource.
curl -X GET https://{server}/api/tenants/{client}/{connection}/docs/modules/wm/resources/workorder \
-H 'Authorization: Bearer {accessToken}'
On Key responds with a list of Resource Actions that are available for the WorkOrder
Resource.
{
"name": "WorkOrder",
"self": {
"href": "api/tenants/{client}/{connection}/DOCS/Modules/WM/Resources/WorkOrder",
"method": "GET",
"module": "WM",
"resource": "WorkOrder"
},
"primaryActions": {
"fetch": {
"doc": "api/tenants/{client}/{connection}/DOCS/Modules/WM/Resources/WorkOrder/Actions/GetWorkOrder",
"href": "api/tenants/{client}/{connection}/Modules/WM/WorkOrders/{WorkOrder->Id}",
"method": "GET",
"module": "WM",
"resource": "WorkOrder",
"resourceAction": "GetWorkOrder"
},
"batchFetch": {
"doc": "api/tenants/{client}/{connection}/DOCS/Modules/WM/Resources/WorkOrder/Actions/BatchGetWorkOrder",
"href": "api/tenants/{client}/{connection}/Modules/WM/WorkOrders/Batch/{ids:IdList}",
"method": "GET",
"module": "WM",
"resource": "WorkOrder",
"resourceAction": "BatchGetWorkOrder"
},
"query": {
"doc": "api/tenants/{client}/{connection}/DOCS/Modules/WM/Resources/WorkOrder/Actions/GetWorkOrderCollection",
"href": "api/tenants/{client}/{connection}/Modules/WM/WorkOrders/",
"method": "GET",
"module": "WM",
"resource": "WorkOrder",
"resourceAction": "GetWorkOrderCollection"
},
"create": {
"doc": "api/tenants/{client}/{connection}/DOCS/Modules/WM/Resources/WorkOrder/Actions/CreateWorkOrder",
"href": "api/tenants/{client}/{connection}/Modules/WM/WorkOrders/",
"method": "POST",
"module": "WM",
"resource": "WorkOrder",
"resourceAction": "CreateWorkOrder"
},
"batchCreate": {
"doc": "api/tenants/{client}/{connection}/DOCS/Modules/WM/Resources/WorkOrder/Actions/BatchCreateWorkOrder",
"href": "api/tenants/{client}/{connection}/Modules/WM/WorkOrders/Batch",
"method": "POST",
"module": "WM",
"resource": "WorkOrder",
"resourceAction": "BatchCreateWorkOrder"
},
"update": {
"doc": "api/tenants/{client}/{connection}/DOCS/Modules/WM/Resources/WorkOrder/Actions/UpdateWorkOrder",
"href": "api/tenants/{client}/{connection}/Modules/WM/WorkOrders/{WorkOrder->Id}",
"method": "PATCH",
"module": "WM",
"resource": "WorkOrder",
"resourceAction": "UpdateWorkOrder"
},
"batchUpdate": {
"doc": "api/tenants/{client}/{connection}/DOCS/Modules/WM/Resources/WorkOrder/Actions/BatchUpdateWorkOrder",
"href": "api/tenants/{client}/{connection}/Modules/WM/WorkOrders/Batch",
"method": "PATCH",
"module": "WM",
"resource": "WorkOrder",
"resourceAction": "BatchUpdateWorkOrder"
}
},
"links": [
...
]
}
Every Resource Action includes a doc
link that points to the metadata endpoint for retrieving more information about a specific Work Order
Resource Action.
Resource Action Metadata
To inspect the metadata for a specific Resource Action, use the doc
link to send a GET
request as illustrated in the following GetWorkOrderCollection
Resource Action request.
curl -X GET https://{server}/api/tenants/{client}/{connection}/docs/modules/wm/resources/workorder/actions/getworkordercollection \
-H 'Authorization: Bearer {accessToken}'
On Key responds with all the metadata information for the GetWorkOrderCollection
Resource Action.
{
"type": "Query",
"name": "GetWorkOrderCollection",
"endpoint": {
"doc": "api/tenants/{client}/{connection}/DOCS/Modules/WM/Resources/WorkOrder/Actions/GetWorkOrderCollection",
"href": "api/tenants/{client}/{connection}/Modules/WM/WorkOrders/",
"method": "GET",
"module": "WM",
"resource": "WorkOrder",
"resourceAction": "GetWorkOrderCollection",
"type": "primaryAction"
},
"allowAnonymous": false,
"resource": {
"href": "api/tenants/{client}/{connection}/DOCS/Modules/WM/Resources/WorkOrder",
"method": "GET",
"module": "WM",
"resource": "WorkOrder"
},
"self": {
"href": "api/tenants/{client}/{connection}/DOCS/Modules/WM/Resources/WorkOrder/Actions/GetWorkOrderCollection",
"method": "GET",
"type": "documentation"
},
"uriFeatures": {
"canSubSelect": true,
"canFilter": true,
"canOrder": true,
"canPage": true,
"canRunAsync": false,
"canSchedule": false,
"canScheduleRecurring": false
},
"response": {
"contentType": "application/vnd.onkey.entitycollectionpage+json",
"features": {
"canSaveCustomInstance": true,
"canExpand": true,
"canOrder": true,
"queryStringParameters": null
},
"entity": {
"name": "WorkOrder",
"metadataTree": {
"href": "api/tenants/{client}/{connection}/DOCS/Modules/WM/Metadata/Entities/WorkOrder/Tree",
"method": "GET",
"rel": "Expand",
"type": "navigation"
}
},
"properties": [
{
"name": "id",
"path": "WorkOrder->Id",
"dataType": "integer",
"format": "int64",
"validations": []
},
{
"name": "code",
"path": "WorkOrder->Code",
"dataType": "string",
"validations": [
{
"type": "null",
"origin": "domain",
"value": false
},
{
"type": "minLength",
"origin": "domain",
"value": 1
},
{
"type": "maxLength",
"origin": "domain",
"value": 50
}
]
},
{
"name": "description",
"path": "WorkOrder->Description",
"dataType": "string",
"translatable": true,
"validations": [
{
"type": "null",
"origin": "domain",
"value": false
},
{
"type": "minLength",
"origin": "domain",
"value": 1
},
{
"type": "maxLength",
"origin": "domain",
"value": 100
}
]
},
...
]
}
}
Besides some general information about the GetWorkOrderCollection
Resource Action, some values are important for customisation purposes:
Value | Description |
---|---|
response.canSaveCustomInstance |
Can a customisation be created for the endpoint |
response.canExpand |
Can the customisation expand to include additional information |
response.canOrder |
Can the customisation include an orderBy clause |
properties |
List of properties that are available to include in a customisation |
Notice that for every property, additional information such as the validation rules, data type and more are included to give full context for all the data that is allowed for the Resource Action.
For Resource Actions that are executed using a POST
or PUT
request, the information is stored within a request
property as illustrated below for the CreateWorkOrder
Resource Action:
{
"type": "Create",
"name": "CreateWorkOrder",
"endpoint": {
"doc": "api/tenants/{client}/{connection}/DOCS/Modules/WM/Resources/WorkOrder/Actions/CreateWorkOrder",
"href": "api/tenants/{client}/{connection}/Modules/WM/WorkOrders/",
"method": "POST",
"module": "WM",
"resource": "WorkOrder",
"resourceAction": "CreateWorkOrder",
"type": "primaryAction"
},
"allowAnonymous": false,
"resource": {
"href": "api/tenants/{client}/{connection}/DOCS/Modules/WM/Resources/WorkOrder",
"method": "GET",
"module": "WM",
"resource": "WorkOrder"
},
"self": {
"href": "api/tenants/{client}/{connection}/DOCS/Modules/WM/Resources/WorkOrder/Actions/CreateWorkOrder",
"method": "GET",
"type": "documentation"
},
"uriFeatures": {
"canSubSelect": false,
"canFilter": false,
"canOrder": false,
"canPage": false,
"canRunAsync": true,
"canSchedule": true,
"canScheduleRecurring": false
},
"request": {
"contentType": "application/vnd.onkey.entity+json",
"features": {
"canSaveCustomInstance": false,
"canExpand": false,
"canOrder": false,
"queryStringParameters": null
},
"entity": {
"name": "WorkOrder",
"metadataTree": {
"href": "api/tenants/{client}/{connection}/DOCS/Modules/WM/Metadata/Entities/WorkOrder/Tree",
"method": "GET",
"rel": "Expand",
"type": "navigation"
}
},
"properties": [
{
"name": "assetId",
"path": "WorkOrder->Asset_Id",
"dataType": "integer",
"format": "int64",
"originalSourcePath": "Asset->Id",
"referenceGroup": "asset",
"validations": [
{
"type": "minValue",
"exclusive": true,
"origin": "domain",
"value": 1
}
]
},
{
"name": "code",
"path": "WorkOrder->Code",
"dataType": "string",
"systemGenerated": true,
"validations": [
{
"type": "null",
"origin": "domain",
"value": false
},
{
"type": "minLength",
"origin": "domain",
"value": 1
},
{
"type": "maxLength",
"origin": "domain",
"value": 50
}
]
}, ...
]
}
}
Example
To illustrate the resource customisation feature, consider a requirement to create a Work TODO dashboard. The TODO dashboard must contain swim-lanes/groupings of Work Orders grouped by Work Order status. The Work Orders must be ordered by when the work needs to be completed and only display a small subset of Work Order information on a Work Order card visualisation.
Create Customisation
After analysing and inspecting the metadata endpoints for the Work Order
Resource, we identify the GetWorkOrderCollection
Resource Action as the endpoint to customise as it returns a collection of Work Orders. To cater for the statuses/groupings, we add a filter to the customisation so that all Work Orders returned for a request are of the same status. To allow re-using the same customisation for different statuses, we parameterise the filter so that we do not hard-code the customisation to use a specific status only. We also sort the Work Orders based on when they need to be completed.
The following POST
request illustrates the complete request to create the corresponding GetWorkOrderCollection
resource action customisation.
curl -X POST https://{server}/api/tenants/{client}/{connection}/docs/modules/wm/resources/workorder/actions/getworkordercollection/customisations \
-H 'Content-Type: application/vnd.onkey.customresourceactioncreate+json' \
-H 'Authorization: Bearer {accessToken}' \
-d '{
"name": "WorkToDoBasedOnStatusSummaryList",
"description": "A list of TODO Work Orders with their summary information",
"isTemp": false,
"restrictionLevel": "Public",
"response": {
"properties": [
{
"path": "WorkOrder->Code"
},
{
"path": "WorkOrder->Description"
},
{
"path": "WorkOrder->Asset_Code"
},
{
"path": "WorkOrder->Asset_Description"
},
{
"path": "WorkOrder->CompleteBy"
},
{
"path": "WorkOrder->WorkRequired"
},
{
"path": "WorkOrder->Site_Code"
},
{
"path": "WorkOrder->Site_Description"
},
{
"path": "WorkOrder->Requester"
}
],
"orderBy": "WorkOrder->RequiredBy",
"criteria": "WorkOrder->Status_Code = @Status"
}
}'
Some of the values included with the request are:
Value | Description |
---|---|
name |
An unique name for the customisation |
description |
A description for the customisation |
isTemp |
If true , the customisation will be created temporarily and cleaned up on a schedule. Set to false to ensure that the customisation gets persisted indefinitely to the database. |
restrictionLevel |
Access level for the customisation:
|
response |
definition of the response customisation |
response.properties |
list of properties to return |
response.orderBy |
order to return data in |
response.criteria |
criteria used to filter the data |
Once created, On Key will respond with a 201 Created
status code and include the unique customisationId
for the customisation using the OnKey-Resource-Id
header.
HTTP/1.1 201 Created
OnKey-Resource-Id: 1631206385100001
OnKey-Resource-Location: api/tenants/{client}/{connection}/docs/modules/{module:Module}/resources/{resourceName}/actions/{resourceActionName}/customisations/{customisationId:long}
To view the customisation created, issue a GET
request using the customisationId
:
curl -X GET https://{server}/api/tenants/{client}/{connection}/modules/wm/resources/workorder/actions/getworkordercollection/customisations/1631206385100001 \
-H 'Authorization: Bearer {accessToken}'
The response should contain a json
body with the content of the response
property send through with the create customisation POST
request:
{
"id": 1631206385100001,
"version": 1,
"resource": "WorkOrder",
"resourceAction": "GetWorkOrderCollection",
"name": "WorkToDoBasedOnStatusSummaryList",
"description": "A list of TODO Work Orders summary information",
"isTemp": false,
"response": {
"properties": [
{
"path": "WorkOrder->Code"
},
{
"path": "WorkOrder->Description"
},
{
"path": "WorkOrder->Asset_Code"
},
{
"path": "WorkOrder->Asset_Description"
},
{
"path": "WorkOrder->CompleteBy"
},
{
"path": "WorkOrder->WorkRequired"
},
{
"path": "WorkOrder->Site_Code"
},
{
"path": "WorkOrder->Site_Description"
},
{
"path": "WorkOrder->Requester"
}
],
"criteria": "WorkOrder->Status_Code = @Status",
"orderBy": "WorkOrder->RequiredBy"
},
"links": [ ...
],
"restrictionLevel": "Public"
}
Execute Customisation
To execute the resource customisation, we append the ?cid={customisationId}
to the normal GetWorkOrderCollection
endpoint. If we specify a valid customisationId
On Key will, instead of executing the system defined GetWorkOrderCollection
resource action, load and execute the customisation instead.
curl -X GET https://{server}/api/tenants/{client}/{connection}/modules/wm/workorders/?cid=1631206385100001 \
-H 'Authorization: Bearer {accessToken}'
When we send the request, On Key responds with an error indicating that the specific customisation cannot be executed as we did not specify a value for the @Status
parameter.
{
"messages": [
{
"code": "Core_UnexpectedError_Message",
"message": "An unexpected error occurred: Core_Grammars_UnknownParameterReference: Could not find a parameter reference '@Status'. Check that parameter reference is added to $param list",
"severity": "error"
}
]
}
We need to add a $param fragment with a valid status code for the @Status
parameter.
curl -X GET https://{server}/api/tenants/{client}/{connection}/modules/wm/workorders/?cid=1631206385100001&$param=@Status:'AP' \
-H 'Authorization: Bearer {accessToken}'
Once added, On Key responds with a collection of sorted Work Orders for the specific status.
{
"count": 150,
"self": {
"href": "api/tenants/{client}/{connection}/Modules/WM/WorkOrders/?cid=1631206385100001&$param=@Code%3A%27AP%27&$top=2001&$skip=0",
"method": "GET",
"type": "navigation"
},
"items": [
{
"class": "DomainDynamicRecord",
"properties": {
"code": "S00156",
"description": "Task(s) for the following Intervals: Week; ",
"assetCode": "BOIL002",
"assetDescription": "Coal Boiler",
"completeBy": "2005-01-09T22:00:00.0000000Z",
"workRequired": "Task(s) for the following Intervals: Week; ",
"siteCode": "A31",
"siteDescription": "ABC Mining Port Alfred",
"requester": "Scheduler",
"requiredBy": "2005-01-09T22:00:00.0000000Z"
},
"links": []
},
{
"class": "DomainDynamicRecord",
"properties": {
"code": "S00172",
"description": "Task(s) for the following Intervals: Week; ",
"assetCode": "BOIL002",
"assetDescription": "Coal Boiler",
"completeBy": "2005-01-09T22:00:00.0000000Z",
"workRequired": "Task(s) for the following Intervals: Week; ",
"siteCode": "A31",
"siteDescription": "ABC Mining Port Alfred",
"requester": "Scheduler",
"requiredBy": "2005-01-09T22:00:00.0000000Z"
},
"links": []
}, ...
]
}
To populate the additional swim-lanes/groupings, we can issue the same request using different @Status
parameter values.
Tip
It is also possible to issue a single request to get all the work orders for the different statuses associated with the swim-lanes/groupings. Include the status as part of the properties being returned so that you can group on it. Change the filter to, instead of using a @Status
parameter, use an IN
operator with an array of possible status values, i.e. "criteria": "WorkOrder->Status_Code IN ('AP','CL','AF')"
Change Customisation Execution
Even though we can project, filter and order the data as part of defining a Resource Customisation, we can still use OKQL to further filter, project and page through the data returned by a customisation.
Important
The scope of what data you can further project or filter on is limited to the data used by/defined within your customisation. You cannot use data that is not included in your customisation definition.
To illustrate, say we want to limit the TODO dashboard to only show the TODO work for a specific Site
. As SiteCode
is included in our customisation definition, we can execute the customisation with an additional $filter
as illustrated below:
curl -X GET https://{server}/api/tenants/{client}/{connection}/modules/wm/workorders/?cid=1631206385100001&$param=@Status:'AP'&$filter=siteCode='A31' \
-H 'Authorization: Bearer {accessToken}'
When executed, the original WorkOrder->Status_Code = @Status
filter of the customisation will be combined with the new siteCode='A31'
filter to create a $filter=WorkOrder->Status_Code = @Status and siteCode='A31'
filter expression. This will return the same information but only for the subset of A31
sites.
If, for some reason, you want to override the default behaviour and exclude the original customisation filter, include an additional ?mergeFilter=false
query string parameter. This will create a $filter=siteCode='A31'
filter expression that will ignore the status criteria when executed as illustrated below:
curl -X GET https://{server}/api/tenants/{client}/{connection}/modules/wm/workorders/?cid=1631206385100001&$param=@Status:'AP'&$filter=siteCode='A31'&mergeFilter=false \
-H 'Authorization: Bearer {accessToken}'