Context


Every data actions (creation, edition or deletion) is handled by xDM by inserting data into the source tables.

There is no native way to only trigger the certification process based on one of those action types.

But business cases might require developers to do so.


For example, you might need to only process field updates for records already present in the MDM.

So, here is a step-by-step guide on how to implement a working solution for this use case in the context of REST API integration.


Summarized Solution

This solution is based on the general principle of implementing a validation that will check whether this record's ID already exists in the MDM. If this is the case, then the validation can go through to process and certify the update. Otherwise, the data sent would fall into the error table. 

This simple validation is able to work, because a checkout is performed by the REST API as soon as a call is launched, thus creating a link with an existing master (and so golden) if there is.


So this solution is only working for REST API integration, another implementation needs to be thought out for SQL integration.


Detailed Solution


Create a validation with validation scope set to "none" and condition is "GoldenRecord.ID is not null". The scope needs to be set to none, to still be able to create records otherwise (authoring, publisher or otherwise configured REST API calls).
 

Here is a simple example implemented on a PRODUCT entity 


Then, when submitting an integration, said newly created validation needs to be declared in the optionsPerEntity:

{
  "action": "CREATE_LOAD_AND_SUBMIT",
  "programName": "curl",
  "loadDescription": "Load Customers",
  "jobName": "INTEGRATE_ALL",
  "submitAs": "semadmin",
  "persistOptions": {
    "responsePayload": "SUMMARY_AND_RECORDS",
    "persistMode": "IF_NO_ERROR_OR_MATCH",
    "defaultPublisherId": "CRM",
    "optionsPerEntity": {
      "Product": {
        "enrichers": "ALL",
        "validations": [
            {
                "validationType": "CHECK",
                "validationName": "UpdateREST"
            }]

      }
    },
    "missingIdBehavior": "GENERATE"
  },
  "persistRecords": {
    "Product": [
      {
        "ProductID": 2,
        "ProductName": "test02"
      }
    ]
  }
}

In case of creation, a "PERSIST_CANCELLED" is returned:

{    "status": "PERSIST_CANCELLED",    "load": {        "loadId": 4,        "loadStatus": "CANCELED",        "loadCreator": "semadmin",        "loadCreationDate": "2024-09-27T11:56:47.862Z",        "programName": "curl",        "loadDescription": "Load Customers",        "numberOfJobExecutions": 0,        "submitInterval": -1,        "submittable": true,        "loadType": "EXTERNAL_LOAD"    },    "persistSummary": {        "Product": {            "recordsPersisted": 1,            "recordsWithFailedValidations": 1,            "recordsWithPotentialMatches": 0        }    },    "records": {        "Product": [            {                "entityName": "Product",                "recordValues": {                    "ProductID": 2,                    "ProductName": "test02"                },                "failedValidations": [                    {                        "validationType": "CHECK",                        "validationName": "UpdateREST",                        "validationErrorMessage": "Validation failed for Update REST"                    }                ],                "certificationSteps": {                    "enrichers": [],                    "validations": [                        {                            "validationType": "CHECK",                            "validationName": "UpdateREST"                        }                    ],                    "matchRules": []                },                "potentialMatches": []            }        ]    }}

But if it is an update of an existing records:

{
  "action": "CREATE_LOAD_AND_SUBMIT",
  "programName": "curl",
  "loadDescription": "Load Customers",
  "jobName": "INTEGRATE_ALL",
  "submitAs": "semadmin",
  "persistOptions": {
    "responsePayload": "SUMMARY_AND_RECORDS",
    "persistMode": "IF_NO_ERROR_OR_MATCH",
    "defaultPublisherId": "CRM",
    "optionsPerEntity": {
      "Product": {
        "enrichers": "ALL",
        "validations": [
            {
                "validationType": "CHECK",
                "validationName": "UpdateREST"
            }]

      }
    },
    "missingIdBehavior": "GENERATE"
  },
  "persistRecords": {
    "Product": [
      {
        "ProductID": 1,
        "ProductName": "test01x"
      }
    ]
  }
}

A "PERSISTED" is returned:

{    "status": "PERSISTED",    "load": {        "loadId": 5,        "loadStatus": "PENDING",        "loadCreator": "semadmin",        "loadCreationDate": "2024-09-27T12:03:14.446Z",        "programName": "curl",        "loadDescription": "Load Customers",        "loadSubmitDate": "2024-09-27T12:03:14.497Z",        "batchSubmitter": "semadmin",        "batchId": 4,        "integrationJobName": "INTEGRATE_ALL",        "integrationJobQueueName": "Default",        "numberOfJobExecutions": 0,        "submitInterval": -1,        "submittable": true,        "loadType": "EXTERNAL_LOAD"    },    "persistSummary": {        "Product": {            "recordsPersisted": 1,            "recordsWithFailedValidations": 0,            "recordsWithPotentialMatches": 0        }    },    "records": {        "Product": [            {                "entityName": "Product",                "recordValues": {                    "ProductID": 1,                    "ProductName": "test01x"                },                "failedValidations": [],                "certificationSteps": {                    "enrichers": [],                    "validations": [                        {                            "validationType": "CHECK",                            "validationName": "UpdateREST"                        }                    ],                    "matchRules": []                },                "potentialMatches": []            }        ]    }}