Table of Contents

Bulk Requests

In addition to supporting operations that act on a single resource, most resources can also be actioned in bulk. These bulk requests can be used to efficiently action multiple records in a single API request and are especially useful in different data integration scenarios.

The different kinds of bulk requests supported are:

  • Batch requests
  • Match Update requests
  • Import requests

Execution Mode

When submitting a bulk API request, the API request can specify an execution mode query parameter to indicate how the request should be executed. A value of ?mode=AllOrNone will run all records in the request within a single transaction and return a single response that contains a success/failure indication that applies to all the records in the request. If any record fails, none of the changes in the request will be applied.

A value of ?mode=PerRecord will run all records in the request within their own transaction and return a single response that contains multiple success/failure indications for every record in the request. Individual records fail or succeed without affecting the outcome of the other records within the same request.

Note

If no mode is specified, On Key defaults to AllOrNone.

Batch Requests

The On Key API supports batch CRUD operations for most resources. A batch CRUD operation can action multiple records in a single API request.

Batch Create

When attempting to create a batch of new records for a resource, a unique identifier (also known as a userObjectId) needs to be specified for every record in the batch. The unique userObjectId allows On Key to associate and echo back any error condition for a specific record in the API response.

To illustrate, consider the following json payload for creating a batch of records for the Asset Importance resource. In this scenario, record2 does not include a description property which violates the business rules for creating a new Asset Importance resource.

curl -v -X POST https://{server}/api/tenants/{client}/{connection}/modules/risk/assetimportances/batch?mode=PerRecord \
-H 'Content-Type:application/vnd.onkey.entitycollection+json' \
-H 'Authorization: Bearer {accessToken}' \
-d '[{
    "userObjectId" : "record1",
    "properties": {
      "code": "ABC",
      "description": "111111",
      "notes": "notes1",
      "weight": 1
    }
},
{
    "userObjectId" : "record2",
    "properties": {
      "code": "DEF",
      "description": null,
      "notes": "notes2",
      "weight": 2
    }
}]'

When executing this request using ?mode=PerRecord, the response code will be 200 OK with the following response body:

{
    "messages": [
        {
            "code": "Core_Data_RecordCreated",
            "message": "Record successfully created",
            "objectId": "1543841451656001",
            "objectType": "AssetImportance",
            "severity": "information",
            "userObjectId": "record1"
        },
        {
            "code": "Core_LengthValidator",
            "message": "{AssetImportance->Description} must be between 1 and 100 characters. You entered 0 characters",
            "objectType": "AssetImportance",
            "properties": [
                "AssetImportance->Description"
            ],
            "severity": "error",
            "userObjectId": "record2"
        }
    ]
}

Notice that the userObjectId is echoed back for both record1 and record2 to report on whether every record within the batch was successfully created or not. Also note the unique objectId returned for the inserted record1.

The same request executed using ?mode=AllOrNone will result in a response code of 400 Bad Request with the following response body:

{
    "messages": [
        {
            "code": "Core_Resources_SystemRequiredPropertyMissing",
            "message": "{AssetImportance->Description} should not be missing or null",
            "objectType": "AssetImportance",
            "properties": [
                "AssetImportance->Description"
            ],
            "severity": "error",
            "userObjectId": "record2"
        }
    ]
}

Notice that the response now only contains the error for record2 and that record1 was not inserted due to the the execution mode of AllOrNone.

Batch Update and Delete

To update or delete a batch of existing records, the API request needs to specify the id and version for every record in the batch. The id will be used to communicate the success or failure for every record in the batch based on the execution mode selected.

To illustrate, consider the following example for updating a batch of Asset Importance resources.

curl -v -X PATCH https://{server}/api/tenants/{client}/{connection}/modules/risk/assetimportances/batch?mode=PerRecord \
-H 'Content-Type:application/vnd.onkey.entitycollection+json' \
-H 'Authorization: Bearer {accessToken}' \
-d '[
{
    "id": 1543843155165003,
    "version": 1,
    "operations": [
        {
            "path": "description",
            "value": "changed AA"
        },
    ]
},
{
    "id": 1543843155164002,
    "version": 1,
    "operations": [
        {
            "path": "description",
            "value": "changed BB"
        },
        {
            "path": "notes",
            "value": "some notes update"
        }
    ]
}]'

When executing this valid request using ?mode=PerRecord, the response code will be 200 OK with the following response body:

{
    "messages": [
        {
            "code": "Core_Data_RecordUpdated",
            "message": "Record successfully updated",
            "objectId": "1543843155164002",
            "objectType": "AssetImportance",
            "severity": "information"
        },
        {
            "code": "Core_Data_RecordUpdated",
            "message": "Record successfully updated",
            "objectId": "1543843155164002",
            "severity": "information"
        }
    ]
}

Notice that the objectId is echoed back and contains the unique identity for every record processed in the batch.

An invalid request executed with ?mode=AllOrNone will result in a 400 Bad Request status code with the following response body:

{
    "messages": [
        {
            "code": "Core_LengthValidator",
            "message": "{AssetImportance->Description} must be between 1 and 100 characters. You entered 0 characters",
            "objectId": "1543844764239005",
            "objectType": "AssetImportance",
            "properties": [
                "AssetImportance->Description"
            ],
            "severity": "error"
        }
    ]
}

Notice the objectId in the response body to indicate the record in the batch that failed.

Match Update Requests

The On Key API supports the match update of properties for a resource. A match update will update the same set of properties for a batch of records for the same resource to all have the same value (i.e. they will all match) across the different record instances.

Note

Match update is only supported for a select sub-set of properties (if any) for a resource. Use the Hypermedia associated with a resource to see if match update operation is available.

To illustrate, consider the following example for updating the description property of the Asset Importance resource to have the same value for two different records:

curl -v -X PATCH https://{server}/api/tenants/{client}/{connection}/modules/risk/assetimportances/matchbatch?mode=PerRecord \
-H 'Content-Type:application/vnd.onkey.entitymatchupdatecollection+json' \
-H 'Authorization: Bearer {accessToken}' \
-d '{
    "records": [
        {
            "id": 1543843155165003,
            "version": 1
        },
        {
            "id": 1543843155165002,
            "version": 3
        }
    ],
    "operations": [
        {
            "path": "description",
            "value": "Same value for all records"
        }
    ]
}'

As with batch requests, match update requests can be executed using either the AllOrNone or PerRecord execution mode. The same error mechanism used for Batch Update and Delete responses also applies to match update responses.

Import Requests

The On Key API supports a generic Import request to action (Insert, Update, Delete or Merge) different types of records within a single POST request. The import request can be scheduled and executed asynchronously and supports the same execution mode and error handling behaviours as existing batch requests. Schema converters can be used within the request to resolve reference lookups and to uniquely identify the records to action.

Records can be grouped and executed in order by appending the optional ordered=true query string parameter to the request uri and by assigning individual records within the request the same GroupOrder identifier. Groups with a smaller GroupOrder identifier are actioned first.

The Merge action will check whether an existing record exists. If not, a new record will be created, otherwise the existing record will be updated. This is especially useful in system-to-system integration scenarios where an integration flow can be setup to synchronize data between On Key and other systems.

To illustrate, consider the following request where a single, ordered import is used to assign a Resource Trade to a staff member Resource and then set the same Resource Trade as the default for the staff member Resource:

curl -v -X PATCH https://{server}/api/tenants/{client}/{connection}/modules/system/imports?mode=PerRecord&ordered=true \
-H 'Content-Type:application/vnd.onkey.entityimportcollection+json' \
-H 'Authorization: Bearer {accessToken}' \
-d '[
{
    "entityType": "ResourceTrade",
    "action": "Merge",
    "userObjectId": "record1",
    "groupOrder": "1",
    "Id": {
        "converter": "ReferenceLookup",
        "type": "Custom",
        "properties": {
            "ResourceTrade->Resource_Code": "SHBE",
            "ResourceTrade->Trade_Code": "HAND"
        }
    },
    "properties": {
        "resourceId": {
            "converter": "ReferenceLookup",
            "code": "SHBE"
        },
        "tradeId": {
            "converter": "ReferenceLookup",
            "code": "HAND"
        },
        "permissionTreeId": {
            "converter": "ReferenceLookup",
            "code": "A20"
        }
    }
  },
  {
    "entityType": "Resource",
    "action": "Update",
    "userObjectId": "record2",
    "groupOrder": "2",
    "Id": {
        "converter": "ReferenceLookup",
        "type": "Custom",
        "properties": {
          "Resource->Code": "SHBE"
        }
    },
    "properties": {
        "defaultResourceTradeId": {
            "converter": "ReferenceLookup",
            "type": "Custom",
            "properties": {
                "ResourceTrade->Resource_Code": "SHBE",
                "ResourceTrade->Trade_Code": "HAND"
            }
        }
    }
  }
]'

Notice the use of the ?ordered=true query string parameter and that the two records within the request have different groupOrder identifiers. This ensures that the request for assigning the Resource Trade to the staff member Resource executes first. A merge action is used to create or update the Resource Trade using Reference Lookup Schema converters to identify the staff member Resource and Trade. The second record subsequently uses the same reference lookup to find and assign the id of the Resource Trade created to the defaultResourceTradeId of the same staff member Resource identified by the SHBE code.

When executing this valid request using ?mode=PerRecord, the response code will be 200 OK with the following response body:

{
    "messages": [
        {
            "code": "Core_Data_RecordCreated",
            "message": "Record successfully created",
            "objectId": "1624859842827473",
            "objectType": "ResourceTrade",
            "severity": "information",
            "userObjectId": "record1"
        },
        {
            "code": "Core_Data_RecordUpdated",
            "message": "Record successfully updated",
            "objectId": "5000001002",
            "objectType": "Resource",
            "severity": "information",
            "userObjectId": "record2"
        }
    ]
}