ServiceNowのスクリプト-基本文法からScripted REST APIまで

### ServiceNowの基本コードまとめ
ServiceNowの基本コードといえるものをまとめます。
参考はChuck TomasiのYoutube動画です。


<details><summary>システムログ出力</summary>

```javascript
gs.info('Hello, world!');
```
</details>

<details><summary>サーバースクリプト基本</summary>

```javascript
var gr = new GlideRecord('task');
gr.addActiveQuery();
gr.query();

while (gr.next()) {
    gs.info(gr.getValue('number'));
}
```
</details>

<details><summary>クライアントスクリプト基本</summary>

```javascript
function onLoad() {

  alert('Current state value is: ' + g_form.getValue('state'));

}
```
</details>

<details><summary>変数例と一般的な命名規則</summary>

```javascript
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式
```
</details>

<details><summary>オペレーター式</summary>

```javascript
// 値の代入
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);

```
</details>

<details><summary>String型</summary>

```javascript
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);
```
</details>

<details><summary>特殊文字</summary>

```javascript
// \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(\\)');
```
</details>

<details><summary>型変換と型確認</summary>

```javascript
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);
```
</details>

<details><summary>コメントアウト</summary>

```javascript
// This is a single line comment

/* This is another way to comment */
```
</details>

<details><summary>算術演算子</summary>

```javascript
var a = 0;
var b = 1;
gs.info(a < b);

var n = '3';
var i = 3;
gs.info(n == i); // ？？？
gs.info(i = 4); // 代入
```
</details>

<details><summary>if文</summary>

```javascript
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');
```
</details>

<details><summary>boolean型</summary>

```javascript
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');
```
</details>

<details><summary>三項演算子</summary>

```javascript
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);
```
</details>

<details><summary>switch文</summary>

```javascript
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);
```
</details>

<details><summary>true/false</summary>

```javascript
var boolTrue = true;
var boolFalse = false;
gs.info('boolTrue=' + boolTrue + ' boolFalse=' + boolFalse);
```
</details>

<details><summary>値がどう評価されるかクイズ</summary>

```javascript
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'));
```
</details>

<details><summary>ループ文</summary>

```javascript
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');
```
</details>

<details><summary>for文の継続</summary>

```javascript
for (var i = 0; i < 5; i++) {
  gs.info(i);
}
gs.info('done i=' + i);
```
</details>

<details><summary>do-while</summary>

```javascript
var i = 0;
gs.info('start');
do {
  gs.info('i=' + i);
  ++i;
} while (i < 5);
gs.info('done i=' + i);
```
</details>

<details><summary>ネスト式ループ</summary>

```javascript
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);
```
</details>

<details><summary>関数定義</summary>

```javascript
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);

```
</details>

<details><summary>try/catch</summary>

```javascript
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');
}
```
</details>

<details><summary>DBクエリ</summary>

```javascript
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'));
}
```
</details>

<details><summary>配列型</summary>

```javascript
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]);
}
```
</details>

<details><summary>foreach</summary>

```javascript
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);
});
```
</details>

<details><summary>配列処理</summary>

```javascript
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'));
```
</details>

<details><summary>ArrayUtil</summary>

```javascript
// 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(', '));
```
</details>

<details><summary>hasownproperty</summary>

```javascript
var vehicle = {
  "year" : 2018,
  "make"  : "Toyota",
  "model" : "Sienna"
};
gs.info(vehicle.hasOwnProperty("year"));  // <== true
gs.info(vehicle.hasOwnProperty("price")); // <== false
```
</details>

<details><summary>object key/value</summary>

```javascript
var vehicle = {
  "year" : 2018,
  "make"  : "Toyota",
  "model" : "Sienna"
};
for (var key in vehicle) {
  gs.info('key=' + key + ' value=' + vehicle[key]);
}
```
</details>

<details><summary>配列オブジェクト処理</summary>

```javascript
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);
}
```
</details>

<details><summary>Str化/Parse</summary>

```javascript
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));
```
</details>

<details><summary>string処理</summary>

```javascript
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');
}
```
</details>

<details><summary>再帰</summary>

```javascript
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
```
</details>

<details><summary>class,object.prototype</summary>

```javascript
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());
```
</details>

<details><summary>Objectへの関数渡し</summary>

```javascript
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
```
</details>
<details><summary>継承</summary>

```javascript
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();
```
</details>

<details><summary>Script REST API</summary>

```javascript
(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);
```
</details>

<details><summary>Quiz</summary>

```javascript
// 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);
```
</details>