POST Rest API to populate and update the target table

Mittal_M
Giga Guru

Hi Everyone,

I have a requirement of populating the data from one servicenow CMDB to the staging table of another servicenow CMDB whenever a new record is created or record is updated.

The staging table of another CMDB has two custom fields based on which another team will identify below things and will take care of inserting the data in their CMDB.

1. from which class the data is coming (for ex. cmdb_ci_server) - This is hard coded in Business Rule shown in the Script Below.

2. what is the sys_id of the current record.

Based on this requirement I am using Rest API and I have created the POST message from my instance and also created the Business rule to execute/call the POST. As per the requirement it is working fine and creating the records in the staging table of another CMDB but the only issue which I have is that whenever I update the record in my CMDB a new record / duplicate record is created in staging table instead of updating the record.

Kindly let me know what can be done so that I can achieve the requirement.

Below is the After Business Rule on Insert and Update

(function executeRule(current, previous /*null when async*/) {

try {

var r = new sn_ws.RESTMessageV2('Internal Server to Staging table Test', 'POST');

r.setStringParameterNoEscape('u_environment', current.u_environment); //Choice

r.setStringParameterNoEscape('u_priority', current.u_priority); //Choice

r.setStringParameterNoEscape('u_operatingsystems', current.u_operatingsystems); //String

r.setStringParameterNoEscape('u_owner', current.u_owner); //String

r.setStringParameterNoEscape('name', current.name); //String

r.setStringParameterNoEscape('short_description', current.short_description); //String

r.setStringParameterNoEscape('u_gpc_class', 'cmdb_ci_server'); //String

r.setStringParameterNoEscape('u_gpc_sys_id', current.sys_id); //String

//override authentication profile

//authentication type ='basic'/ 'oauth2'

//r.setAuthentication(authentication type, profile name);

var response = r.execute();

var responseBody = response.getBody();

var httpStatus = response.getStatusCode();

}

catch(ex) {

var message = ex.getMessage();

}

})(current, previous);

Below are the screenshots

1. Staging Table and its fields,

find_real_file.png

2. Duplicate record entries in Staging Table.

find_real_file.png

Thanks
11 REPLIES 11

Hi



When you do the POST call to create a record in the target staging table, the response should contain the sys_id of the record created. So it should not be necessary to do the extra GET call.


Appreciate your quick response.


Sorry if I am bothering you much but let me explain, The requirement is to populate the data from one servicenow CMDB to the staging table of another servicenow CMDB whenever a new record is created or record is updated.


So as per this how Business Rule of Source table will know the sys_id of the field GPC Sys ID (of staging table) which is on target server ?



for example, Server record "Server123" is newly created in Source CMDB table and as per POST method and Business Rule the same record will be populated in Target staging table and the sysid of source record "Server123" will go into "GPC Sys ID" field of target staging table. (please see the screenshot below)


Now if the same server record "Server123" is updated and as per the requirement it should also be updated in the target staging table. (PUT method will do this).



find_real_file.png




I am not able to understand how Business Rule will validate if that the record already exists in the target staging table or not ?



Below is my test code in Business Rule for PUT and POST. please let me know what modifications are required in the code ?



(function executeRule(current, previous /*null when async*/) {



try {


var rput = new sn_ws.RESTMessageV2('Internal Server to Staging table Test', 'PUT');


rput.setStringParameterNoEscape('name', current.name);


rput.setStringParameterNoEscape('u_owner', current.u_owner); //String


rput.setStringParameterNoEscape('u_environment', current.u_environment); //Choice


rput.setStringParameterNoEscape('u_gpc_sys_id', current.sys_id); //String



//override authentication profile


//authentication type ='basic'/ 'oauth2'


//r.setAuthentication(authentication type, profile name);



var responseput = rput.execute();


gs.log('putexecuted ' + responseput);


var responseBodyput = responseput.getBody();


var httpStatusput = responseput.getStatusCode();


}


catch(ex) {


var message = ex.getMessage();


}


}



try {


var r = new sn_ws.RESTMessageV2('Internal Server to Staging table Test', 'POST');


r.setStringParameterNoEscape('u_environment', current.u_environment); //Choice


r.setStringParameterNoEscape('u_priority', current.u_priority); //Choice


r.setStringParameterNoEscape('u_operatingsystems', current.u_operatingsystems); //String


r.setStringParameterNoEscape('u_owner', current.u_owner); //String


r.setStringParameterNoEscape('name', current.name); //String


r.setStringParameterNoEscape('short_description', current.short_description); //String


r.setStringParameterNoEscape('u_gpc_class', 'cmdb_ci_server'); //String


r.setStringParameterNoEscape('u_gpc_sys_id', current.sys_id); //String



//override authentication profile


//authentication type ='basic'/ 'oauth2'


//r.setAuthentication(authentication type, profile name);



var response = r.execute();


var responseBody = response.getBody();


var httpStatus = response.getStatusCode();


}


catch(ex) {


var message = ex.getMessage();


}



})(current, previous);




Thanks,


Mittal.


Thanks

Hi



The ONLY way to update a record in the target table using the default REST API is to use the sys_id of the target record with a PUT or a PATCH



PUT/PATCH https://[instance].service-now.com/api/now/table/{tableName}/{sys_id}



So the process will be


  1. A new CI is created in the source - we know that it will not exist in the target as the CI is new > we POST it to the target and save the sys_id of the target record on the source CI
  2. A CI is modified - if the CI contains a value in the field containing the target record sys_id we know that there is record in the target to be updated -> We PUT/PATCH the record in the target using the updated values
    If the CI does not contain a value for the target sys_id we assume that now record has been created previously > we POST it to the target and save the sys_id of the target record on the source CI

It should be that simple - for me I dont't see the need of using the GPC Sys ID as you cant use it in the REST API - unless you build your own scripted REST api on the target


Thanks for your response, please find my comments below.



  1. A new CI is created in the source - we know that it will not exist in the target as the CI is new > we POST it to the target and save the sys_id of the target record on the source CI
      • (This I have already achieved) Source CMDB table is used to only sync the data or Bulk load the data in the target staging table, hence only target staging table field called "GPC Sys ID" will maintain the "sysid" of the source record so that the another team can understand that this "sysid" is for which record and its their job to update in the their CMDB.


  2. A CI is modified - if the CI contains a value in the field containing the target record sys_id we know that there is record in the target to be updated -> We PUT/PATCH the record in the target using the updated values
    If the CI does not contain a value for the target sys_id we assume that now record has been created previously > we POST it to the target and save the sys_id of the target record on the source CI
      • Challenge here is how to achieve this ?

Note: Source table or CI will not save the sysid of the target staging table record. The purpose is to sync the data in the target staging table.


Thanks

poornachander
Mega Expert

You should have a coalsce field on Target table. GPC Sys ID can be a coalsce field. The API sees for the field if it exists it will UPDATE or else it will create a new Record. for both you can POST.


Hoping your staging table is Import Set table, you can do coalsce on ImportSet/transform map.



If the webservice exposed on target database if not ImportSet based, I would suggest go via ImportSet - REST way as it it looks like straight Table to Table integration