ServiceNowの基本コードまとめ
ServiceNowの基本コードといえるものをまとめます。
参考はChuck TomasiのYoutube動画です。
システムログ出力
gs.info('Hello, world!');
サーバースクリプト基本
var gr = new GlideRecord('task');
gr.addActiveQuery();
gr.query();
while (gr.next()) {
gs.info(gr.getValue('number'));
}
クライアントスクリプト基本
function onLoad() {
alert('Current state value is: ' + g_form.getValue('state'));
}
変数例と一般的な命名規則
var name = 'Chuck'; // string型
var i = 0; // integer型
var answer = true; // boolean型
// 変数命名規則
var c = "http://www.amazon.com"; // ×よくない
var case = 'CASE0010001'; // ×予約語
var lastEntryInTheListWithRelatedRecords = true; // △長すぎる
// personCount // counter/integerを示す
// personList // list式
// personObj // Object式
// personGr // GlideRecord式
オペレーター式
// 値の代入
var a = 12;
var b = 3;
// 値の追加
gs.info(2 + 2);
gs.info(a + 2);
b = b + 2;
// b += 2; // 短縮式
// 1増加
a++;
// 1減少
b--;
// 掛け算
gs.info(a * b);
// 割り算
gs.info(a / b);
// 余り
gs.info('');
gs.info(a);
gs.info(b);
gs.info(a % b);
String型
var firstName = "Chuck";
var lastName = 'Tomasi'; // シングルクォート、ダブルクォート両方ともok
var myCar = "Chuck's Car"; // まぜたら紛らわしいのでよくない
// +で文字列をくっつけること可能
var name = firstName + ' ' + lastName;
gs.info(name);
gs.info('length of name=' + name.length);
特殊文字
// \n = 改行
// \t = タブ
// \\ = バックスラッシュ
// \' = single quote
// \" = double quote
//
gs.info('Single string\nTwo lines');
gs.info('Chuck\'s simple script');
gs.info('Don\'t confuse a forward slash (/) with a backslash(\\)');
型変換と型確認
var i = 5;
var iStr = i.toString();
gs.info(typeof i);
gs.info(typeof iStr);
var n = parseInt(iStr);
gs.info(typeof n + ' n=' + n);
コメントアウト
// This is a single line comment
/* This is another way to comment */
算術演算子
var a = 0;
var b = 1;
gs.info(a < b);
var n = '3';
var i = 3;
gs.info(n == i); // ???
gs.info(i = 4); // 代入
if文
var a = 1;
var b = 3;
var c = 5;
if (a < b)
gs.info('a is less than b');
// else
if (a < b)
gs.info('a is less than b');
else
gs.info('a is greater than or equal to b');
// Else if and else
if (a < b)
gs.info('a is less than b');
else if (a > b)
gs.info('a is greater than b');
else if (a == b)
gs.info('a equals b');
else
gs.info('Uh-oh');
if (a < b)
if (b < c)
gs.info('a b c are in order');
boolean型
var a = 1;
var b = 3;
var c = 5;
if (a < b && b < c)
gs.info('a b c are in order');
if (b > a || b > c)
gs.info('b is greater than one of them.');
// Note, indentation can be deceptive!!!
if (a < b)
if (b < c) {
gs.info('a b c are in order');
gs.info(' that means a is less than c');
}
else
gs.info('a is greater than or equal to b');
var valveOpen = true;
if (valveOpen == true)
gs.info('Valve is currently open');
if (bool)
gs.info('Valve is currently open');
var valveOpen = false;
if (!valveOpen)
gs.info('Valve is currently closed');
三項演算子
var valveOpen = true;
var openStatusString;
if (valveOpen)
openStatusString = 'open';
else
openStatusString = 'closed';
gs.info('1: Valve is currently ' + openStatusString);
// Introducing a shortcut way...
var openStatusString = (valveOpen) ? 'open' : 'closed';
gs.info('2: Valve is currently ' + openStatusString);
switch文
var level = 5;
var message = '';
switch (level) {
case 0:
message = 'Empty';
break;
case 1:
case 2:
message = 'Low';
break;
case 3: // Warning - what's wrong with case 3?
message = 'Medium';
case 4:
message = 'High';
break;
case 5:
message = 'Full';
break;
default:
message = 'Uh-oh!';
}
gs.info('Level=' + level + ' status=' + message);
true/false
var boolTrue = true;
var boolFalse = false;
gs.info('boolTrue=' + boolTrue + ' boolFalse=' + boolFalse);
値がどう評価されるかクイズ
var num = 0; // <== try with different numbers
gs.info(num + ' is ' + ((num) ? 'true' : 'false'));
var string1;
var string2 = null;
var string3 = 'Hello, world!';
gs.info('string1=' + ((string1) ? 'true' : 'false'));
gs.info('string2=' + ((string2) ? 'true' : 'false'));
gs.info('string3=' + ((string3) ? 'true' : 'false'));
ループ文
var i = 0;
while (i < 5) {
gs.info(i);
i++;
}
gs.info('done i=' + i);
//break
var i = 0;
while (true) {
if (i == 5)
break;
gs.info(i);
++i;
}
//continue
var i = 0;
var done = false;
while (!done) {
if (i < 5) {
++i;
gs.info(i + ' done=' + done);
continue;
}
gs.info('I think we are done');
done = true;
}
gs.info(i);
gs.info('done');
for文の継続
for (var i = 0; i < 5; i++) {
gs.info(i);
}
gs.info('done i=' + i);
do-while
var i = 0;
gs.info('start');
do {
gs.info('i=' + i);
++i;
} while (i < 5);
gs.info('done i=' + i);
ネスト式ループ
for (var i = 0; i < 5; i++) {
for (var j = 0; j < 3; j++) {
gs.info('i=' + i + ' j=' + j);
}
}
gs.info('Done i=' + i + ' j=' + j);
関数定義
function sayHello() {
gs.info('Hello');
}
sayHello();
//引数つき関数
function toCelsius(fahrenheit) {
var c = (5 / 9) * (fahrenheit - 32);
gs.info(c);
}
toCelsius(32);
toCelsius(100);
//返り値付きの関数
function toCelsius(fahrenheit) {
return (5 / 9) * (fahrenheit - 32);
}
var c = toCelsius(32);
gs.info(c);
c = toCelsius(212);
gs.info(c);
//ローカル変数の関数
function toCelsius(fahrenheit) {
// c is only known in the function toCelsius()
var c = (5 / 9) * (fahrenheit - 32);
return c;
}
gs.info(c); // What happened?
//自立式の関数
var i = 20;
(function() {
// Local variable
i = 10; // uh-oh, forgot the var!
gs.info('i=' + i);
}());
i = 3;
gs.info('i=' + i);
try/catch
try {
for (var i = 0; i < 5; i++) {
gs.info('i=' + i + ' answer=' + answer);
}
} catch (e) {
gs.error('Uh-oh ' + e.message);
} finally {
gs.info('done');
}
DBクエリ
var incGr = new GlideRecord('incident');
incGr.query();
while (incGr.next()) {
gs.info(incGr.getValue('number'));
}
//クエリ文追加
var incGr = new GlideRecord('incident');
incGr.addQuery('active', true);
incGr.orderBy('number');
incGr.setLimit(5);
incGr.query();
while (incGr.next()) {
gs.info(incGr.getValue('number'));
}
//Getメソッドの型に注意
var incGr = new GlideRecord('incident');
incGr.setLimit(1);
incGr.query();
if (incGr.next()) {
var dotNumber = incGr.number;
var gvNumber = incGr.getValue('number');
gs.info('dotNumber=' + typeof dotNumber + ' gvNumber=' + typeof gvNumber);
}
// Why should I care? I'll show you when we get to arrays...
//1レコードを早くとる秘密
var incGr = new GlideRecord('incident');
if (incGr.get('965c9e5347c12200e0ef563dbb9a7156')) {
gs.info(incGr.getValue('number'));
}
// or...
var incGr = new GlideRecord('incident');
if (incGr.get('number', 'INC0000059')) {
gs.info(incGr.getValue('sys_id'));
}
配列型
var list = [];
list[0] = 1;
list[1] = 3;
list[2] = 5;
gs.info('length of list is: ' + list.length);
//短縮
var list = [1, 3, 5];
//配列処理
var list = [1, 3, 5];
for (var i = 0; i < list.length; i++) {
gs.info('i=' + i + ' value=' + list[i]);
}
// Slightly better
var list = [1, 3, 5];
var len = list.length;
for (var i = 0; i < len; i++) {
gs.info('i=' + i + ' value=' + list[i]);
}
foreach
var list = [1, 3, 5];
list.forEach(myFunction);
function myFunction(item) {
gs.info('myFunction item=' + item);
}
// 埋め込みforeach
var list = ['apple', 'banana', 'orange'];
list.forEach(function (item, index, arr) {
gs.info('embedded function item=' + item + ' index=' + index + ' arr=' + arr);
});
配列処理
var list = ['Chuck', 'Kreg', 'Stacey'];
gs.info('list=' + list);
var list = ['Chuck', 'Kreg', 'Stacey'];
gs.info('join: list=' + list.join(', '));
// push(value1, value2, ..., valueX)
list.push('Dave');
list.push('Andrew');
gs.info('push: list=' + list.join(', '));
// pop()
list.pop();
gs.info('pop: list=' + list.join(', '));
//shift()
var list = ['Chuck', 'Kreg', 'Stacey'];
gs.info('Before shift(), list[0]=' + list[0]);
list.shift();
gs.info('shift: list=' + list.join(', '));
gs.info('After shift(), list[0]=' + list[0]);
// unshift
var list = ['Chuck', 'Kreg', 'Stacey'];
var newLength = list.unshift('Jason', 'Andrew');
gs.info('new length=' + newLength + ' unshift() list=' + list.join(', '));
// spice
var names = ["Eric", "Donna", "Melanie", "Jessie"];
gs.info(names.join(', '));
names.splice(2, 0, "Cary", "Henri");
gs.info(names.join(', '));
//slice
var names = ["Eric", "Donna", "Melanie", "Jessie", "Howard", "Tomasz"];
gs.info(names.join(', '));
var subNames = names.slice(1, 3); // Get names at positions 1 and 2
gs.info(subNames.join(', '));
//reverse
var names = ["Eric", "Donna", "Melanie", "Jessie", "Howard", "Tomasz"];
names.reverse();
gs.info(names.join(', '));
//値の取り出し
var list = [];
var incGr = new GlideRecord('incident');
incGr.addQuery('priority', '1');
incGr.query();
while (incGr.next()) {
list.push(incGr.getValue('sys_id'));
}
gs.info('list=\n' + list.join('\n'));
ArrayUtil
// L25S01 - ArrayUtil
//
var au = new ArrayUtil();
var names = [
"Eric",
"Donna",
"Melanie",
"Jessie",
"Howard",
"Eric",
"Jessie",
"Tomasz"
];
var newNames = au.unique(names);
gs.info(newNames.join(', '));
hasownproperty
var vehicle = {
"year" : 2018,
"make" : "Toyota",
"model" : "Sienna"
};
gs.info(vehicle.hasOwnProperty("year")); // <== true
gs.info(vehicle.hasOwnProperty("price")); // <== false
object key/value
var vehicle = {
"year" : 2018,
"make" : "Toyota",
"model" : "Sienna"
};
for (var key in vehicle) {
gs.info('key=' + key + ' value=' + vehicle[key]);
}
配列オブジェクト処理
var bookList = [
{
"title" : "Harry Potter and the Chamber of Secrets",
"author" : "J.K. Rowling"
},
{
"title" : "Moby Dick",
"author" : "Herman Melville"
},
{
"title" : "A Tale of Two Cities",
"author" : "Charles Dickens"
}
];
var len = bookList.length;
gs.info('Last author=' + bookList[len].author);
for (var i = 0; i < len; i++) {
var book = bookList[i];
gs.info(i + ' - Title: ' + book.title + ' - Author: ' + book.author);
}
Str化/Parse
var bookList = [
{
"title" : "Harry Potter and the Chamber of Secrets",
"author" : "J.K. Rowling"
},
{
"title" : "Moby Dick",
"author" : "Herman Melville"
},
{
"title" : "A Tale of Two Cities",
"author" : "Charles Dickens"
}
];
gs.info(bookList); // That's not very helpful!
var bookListStr = JSON.stringify(bookList);
gs.info(bookListStr); // I can read it - sort of
var bookListStrFormat = JSON.stringify(bookList, null, 4);
gs.info(bookListStrFormat); // Ah - that's better!
// parse
var libraryStr = '[{"title":"Harry Potter and the Chamber of Secrets","author":"J.K. Rowling"},{"title":"Moby Dick","author":"Herman Melville"},{"title":"A Tale of Two Cities","author":"Charles Dickens"}]';
gs.info('length=' + libraryStr.length);
var libraryObj = JSON.parse(libraryStr);
gs.info('length=' + libraryObj.length);
gs.info(JSON.stringify(libraryObj, null, 4));
string処理
var subject = 'Warning: Email is not working';
var pos = subject.indexOf('Email');
gs.info(pos);
var short_description = 'System is displaying error message';
if (short_description.indexOf('error') >= 0) {
gs.info("Error message found");
}
//substring
var str = 'Approved: RITM0010001 - Laptop renewal';
var pos = str.indexOf('RITM');
var ritmNumber = str.substring(pos, pos + 11);
gs.info(ritmNumber);
//Case形式
var firstName = 'Chuck';
var loginName = 'chuck';
if (loginName == firstName) {
gs.info('names match');
} else {
gs.info('names do not match');
}
//upper/lower
var firstName = 'Chuck';
var loginName = 'chuck';
gs.info('firstName=' + firstName.toUpperCase() + ' loginName=' + loginName.toUpperCase());
if (loginName.toUpperCase() == firstName.toUpperCase()) {
gs.info('names match');
} else {
gs.info('names do not match');
}
再帰
function factorial(x) {
// TERMINATION
if (x < 0)
return;
// BASE
if (x === 0)
return 1;
// RECURSION
return x * factorial(x - 1);
}
gs.info(factorial(3)); // 6
class,object.prototype
var person = Class.create();
person.prototype = {
initialize: function() {
this.firstName = '';
this.lastName = '';
},
setFirstName : function(str) {
this.firstName = str;
},
setLastName : function(str) {
this.lastName = str;
},
getDisplayName : function() {
return this.firstName + ' ' + this.lastName;
},
type: person
};
var me = new person();
me.setFirstName('Chuck');
me.setLastName('Tomasi')
gs.info('me=' + me.firstName + ' ' + me.lastName); // Not advised
var name = me.getDisplayName();
gs.info(name);
// initialize
var person = Class.create();
person.prototype = {
initialize: function(str1, str2) {
this.firstName = str1;
this.lastName = str2;
},
setFirstName : function(str) {
this.firstName = str;
},
setLastName : function(str) {
this.lastName = str;
},
getDisplayName : function() {
return this.firstName + ' ' + this.lastName;
},
type: 'person'
};
var me = new person('Chuck', 'Tomasi');
var name = me.getDisplayName();
gs.info(name);
me.setFirstName('Fred');
me.setLastName('Luddy');
gs.info(me.getDisplayName());
Objectへの関数渡し
var item = Class.create();
item.prototype = {
initialize: function() {
},
debugObject : function(obj) {
gs.info('object=' + JSON.stringify(obj, null, 4));
},
type: 'item'
};
var myObj = {
"type" : "vehicle",
"engine" : true,
"wheels" : 4,
"state" : "allocated"
};
var myItem = new item();
myItem.debugObject(myObj); // Loosely coupled
継承
var vehicle = Class.create();
vehicle.prototype = {
initialize: function(year, make, model) {
this.make = make;
this.model = model;
this.year = year;
},
register : function() {
gs.info(this.getDisplayName() + ' registered!');
},
info : function() {
gs.info('Vehicle info: TBD');
},
getDisplayName : function() {
return this.year + ' ' + this.make + ' ' + this.model;
},
type: 'vehicle'
};
var car = Class.create();
car.prototype = Object.extendsObject(vehicle, {
findDealer : function() {
gs.info('Find dealer is not yet implemented');
},
info : function() {
gs.info('Car info: TBD');
},
type: 'car'
});
var v1 = new vehicle('2018', 'John Deere', 'Tractor');
v1.register();
v1.info();
var v2 = new car('2017', 'Honda', 'CR-V');
v2.register();
v2.findDealer();
v2.info();
Script REST API
(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
return "hello, world!";
})(request, response);
// Example Query parameters
(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
// https://<instance_rest_endpoint>?active=true&name=now
var queryParams = request.queryParams;
var isActiveQuery = queryParams.active; //true
var nameQueryVal = queryParams.name; //‘now’
var answer = "Response: active=" + isActiveQuery + " name=" + nameQueryVal;
return answer;
})(request, response);
// Scripted REST API with path parameters
(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
// Example path parameters
// https://instance.service-now.com/api/now/myservice/{tableName}/{id}
// https://instance.service-now.com/api/now/myservice/myApp_table/1234
var pathParams = request.pathParams;
var tableName = pathParams.tableName; //‘myApp_table’
var id = pathParams.id; //‘1234’
var answer = "Response: tableName=" + tableName + " id=" + id;
return answer;
})(request, response);
// Scripted REST API (POST) with request body payload
(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
var name = request.body.data.name;
var id = request.body.data.id;
var color = request.body.data.color;
var answer = "Response: name=" + name + " id=" + id + " color=" + color;
return answer;
})(request, response);
// Scripted REST API with POST and response
(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
var name = request.body.data.name;
var id = request.body.data.id;
var color = request.body.data.color;
// Do some processing here
var answer = {};
answer.status = "OK";
answer.author = "system";
answer.item = {"name" : "Rome", "owner" : "Chuck Tomasi", "count" : 12};
answer.active = true;
response.setBody(answer);
return response;
})(request, response);
Quiz
// Lab 2
//
// What is 3 + 2 * 5?
//
gs.info(3 + 2 * 5); // 13
// Create a three string variables.
// Print the length of each string
// concatenate them together with a new line character and save to a new variable
// Print the new variable and length of the new variable
//
var string1 = 'Chuck';
var string2 = 'Tomasi';
var string3 = 'JavaScript';
gs.info('length1 = ' + string1.length);
gs.info('length2 = ' + string2.length);
gs.info('length3 = ' + string3.length);
var allStrings = string1 + '\n' + string2 + '\n' + string3;
gs.info('allStrings=' + allStrings);
gs.info('length of allStrings=' + allStrings.length);
/*
Output from Scripts - background
*** Script: length1 = 5
*** Script: length2 = 6
*** Script: length3 = 10
*** Script: allStrings=Chuck
Tomasi
JavaScript
*** Script: length of allStrings=23
*/
// Create a script that takes a string variable "Hello world"
// and translates it to at least 3 different languages
// based on a 'language' variable.
// Make the default language English if a match isn't found.
var language = 'German';
var fromString = 'Hello world';
var toString = '';
switch (language) {
case 'German':
toString = 'Hallo Welt';
break;
case 'French':
toString = 'Bonjour le monde';
break;
case 'Spanish':
toString = 'Hola Mundo';
break;
default:
toString = 'Hello, world';
}
gs.info(fromString + ' in ' + language + ' ==> ' + toString);
// Create a script that creates 5 teams of 4 people
// and assigns a unique identifier to each team member.
// The script should display the team number,
// person number, and identifier for that person/team.
// Avoid displaying zeros for a better user experience.
//
var id = 1;
for (var team = 0; team < 5; team++) {
for (var person = 0; person < 4; person++) {
gs.info('id=' + id + ' team=' + team+1 + ' person=' + person+1);
++id;
}
}
// Lab 6a: Create a script to accept a table name and
// return a list records display values.
// Hint: use GlideRecord.getDisplayValue()
//
// @param tableName - name of table to query
// @return array - list of record display values
//
function listRecords(tableName) {
var answer = [];
var recGr = new GlideRecord(tableName);
recGr.query();
while (recGr.next()) {
answer.push(recGr.getDisplayValue());
}
return answer;
}
gs.info(listRecords('incident').join('\n'));
// Lab 6b: Update your previous script to accept a limit parameter.
// Hint: use GlideRecord.setLimit()
//
// @param tableName - name of table to query
// @param limit - integer > 0
// @return array - list of record display values
//
function listRecords(tableName, limit) {
var answer = [];
var recGr = new GlideRecord(tableName);
if (limit && limit > 0) {
recGr.setLimit(limit);
}
recGr.query();
while (recGr.next()) {
answer.push(recGr.getDisplayValue());
}
return answer;
}
gs.info(listRecords('incident', 10).join('\n'));
// Update your previous lab to return the sys_id and
// display value of the records you found using an array of objects.
// Return an array of objects.
//
// @param tableName - name of table to query
// @param limit - integer > 0
// @return array of objects
// {
// "display_value" : <display value>,
// "sys_id" : <sys_id>
// }
//
function listRecords(tableName, limit) {
var answer = [];
var recGr = new GlideRecord(tableName);
if (limit && limit > 0) {
recGr.setLimit(limit);
}
recGr.query();
while (recGr.next()) {
var obj = {};
obj.display_value = recGr.getDisplayValue();
obj.sys_id = recGr.getUniqueValue();
answer.push(obj);
}
return answer;
}
var list = listRecords('incident', 10);
gs.info(JSON.stringify(list, null, 4));
// Lab 8a - Rebuild the previous lab as a scripted REST API
// Use Query parameters to accept the table name and limit
// Return the array of objects in the response body
//
// Get table record display values and sys_ids
//
(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
var queryParams = request.queryParams;
var tableName = queryParams.tableName;
var limit = queryParams.limit;
var answer = [];
var recGr = new GlideRecord(tableName);
if (limit && limit > 0) {
recGr.setLimit(limit);
}
recGr.query();
while (recGr.next()) {
var obj = {};
obj.display_value = recGr.getDisplayValue();
obj.sys_id = recGr.getUniqueValue();
answer.push(obj);
}
response.setBody(answer);
})(request, response);
// Lab 8b Script Include Test Script
//
var list = new SNJS().getRecords('problem', 5);
gs.info(list.length);
// Script Include
var SNJS = Class.create();
SNJS.prototype = {
initialize: function() {
},
getRecords : function(tableName, limit) {
var answer = [];
var recGr = new GlideRecord(tableName);
if (limit && limit > 0) {
recGr.setLimit(limit);
}
recGr.query();
while (recGr.next()) {
var obj = {};
obj.display_value = recGr.getDisplayValue();
obj.sys_id = recGr.getUniqueValue();
answer.push(obj);
}
return answer;
},
type: 'SNJS'
};
// Lab 8b - Rebuild the previous lab using a script include for the core logic
// Use Query parameters to accept the table name and limit
// Return the array of objects in the response body
//
// Get table record display values and sys_ids
//
(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) {
var queryParams = request.queryParams;
var tableName = queryParams.tableName;
var limit. = queryParams.limit;
var list = new SNJS().getRecords(tableName, limit);
response.setBody(list);
})(request, response);