I was asked to present a lab I submitted to
K19 at the local Minnesota ServiceNow
User Group. I thought this would be great so I went down the path of
making this small lab about using import sets.

Here's a link to the
deck.

The short version of this is;

Always use import sets for data from another system, and always store
all the data you can see in that import set so you don't have to get
into the integration to do modifications.

You may hear reasons to not do this;

Objection: "This is just a small SolarWinds import to add to our
network devices, It would be just as fast to write to the table in a
script include."

What you should think: "Sure, but then the moment they change their
data or want to coalesce on something else, you'll have to re-interrogate
the data to map it."

What you should say: "Any integration needs to come in to a import
set table where we will hold the data for a few days so we can transform
the data to our values regardless how the data in that other system
exists.

Objection: "I've done plenty of integrations and this one just runs
on demand to get the start date of a new employee, literally just
populating the variables on RITM"

What you should think: "Sure, until they change their mind and want
it to do something more with some other element they were sharing."

What you should say: "We store all data seen from the integration
for future use in case the need arises to use them based on future work.
This simplifies the integration later for other to work on it.

Objection: "This just adds overhead to what would otherwise be a
simple integration."

What you should think: "It's only overhead if you don't do all
your integrations that way. By being consistent anyone on your team
should be able to quickly identify what needs to be changed.

What you should say: "Being consistent on this lets anyone on the
team quickly work on the same integration without having to explain
every nuance about the integration."

Objection: Bringing in data from a nested source like JSON or XML
doesn't make sense.

What you should should think: There's common ways to flatten that
down.

What you should say: Below are examples of how to flatten JSON.

var flatten = function(data) {
var result = {};
function recurse (cur, prop) {
if (Object(cur) !== cur) {
result[prop] = cur;
} else if (Array.isArray(cur)) {
for(var i=0, l=cur.length; i<l; i++)
recurse(cur[i], prop + "[" + i + "]");
if (l == 0)
result[prop] = [];
} else {
var isEmpty = true;
for (var p in cur) {
isEmpty = false;
recurse(cur[p], prop ? prop+"."+p : p);
}
if (isEmpty && prop)
result[prop] = {};
}
}
recurse(data, "");
return result;
}
var obj = {
name: {
first: "Jace",
last: "Benson"
},
website: "https://blog.jace.pro"
};
gs.info('Normal:');
gs.info(JSON.stringify(obj))
gs.info('Flattened:');
gs.info(JSON.stringify(flatten(obj)));

gs.info('XMLtoJSON Flattened:');
var xmlStr = "";
xmlStr += "<Person>";
xmlStr += " <Name>";
xmlStr += " <First>Jace</First>";
xmlStr += " <Last>Benson</Last>";
xmlStr += " </Name>";
xmlStr += " <Site>";
xmlStr += " https://blog.jace.pro";
xmlStr += " </Site>";
xmlStr += "</Person>";

var xmlObj = gs.xmlToJSON(xmlStr);
//gs.info(JSON.stringify(xmlObj,'',' '));
gs.info(JSON.stringify(flatten(xmlObj)));

/*** Script: Normal:
*** Script:
{
"name": {
"first":"Jace",
"last":"Benson"
},
"website":"https://blog.jace.pro"
}
*** Script: Flattened:
*** Script:
{
"name.first":"Jace",
"name.last":"Benson",
"website":"https://blog.jace.pro"
}
*** Script: XMLtoJSON Flattened:
*** Script:
{
"Person.Site":"https://blog.jace.pro",
"Person.Name.Last":"Benson",
"Person.Name.First":"Jace"
}
***/