Script Include Patterns for ServiceNow
Script Includes are reusable server-side JavaScript libraries that can be called from any server-side script.
Script Include Types
Type Use Case Client Callable
Standard Server-side utilities No
Client Callable GlideAjax from client Yes
On-Demand Lazy loading No
AbstractAjaxProcessor Client-server communication Yes
Standard Script Include (ES5)
// Basic utility class var IncidentUtils = Class.create() IncidentUtils.prototype = { initialize: function () { this.LOG_PREFIX = "[IncidentUtils] " },
/**
- Get incident by number
- @param {string} number - Incident number (INC0010001)
- @returns {GlideRecord|null} - Incident record or null */ getByNumber: function (number) { var gr = new GlideRecord("incident") gr.addQuery("number", number) gr.query() if (gr.next()) { return gr } return null },
/**
- Calculate priority based on impact and urgency
- @param {number} impact - Impact value (1-3)
- @param {number} urgency - Urgency value (1-3)
- @returns {number} - Calculated priority (1-5) */ calculatePriority: function (impact, urgency) { var matrix = { "1-1": 1, "1-2": 2, "1-3": 3, "2-1": 2, "2-2": 3, "2-3": 4, "3-1": 3, "3-2": 4, "3-3": 5, } var key = impact + "-" + urgency return matrix[key] || 4 },
/**
- Get open incidents for user
- @param {string} userSysId - User sys_id
- @returns {Array} - Array of incident objects */ getOpenIncidentsForUser: function (userSysId) { var incidents = [] var gr = new GlideRecord("incident") gr.addQuery("caller_id", userSysId) gr.addQuery("active", true) gr.orderByDesc("opened_at") gr.query()
while (gr.next()) {
incidents.push({
sys_id: gr.getUniqueValue(),
number: gr.getValue("number"),
short_description: gr.getValue("short_description"),
state: gr.state.getDisplayValue(),
priority: gr.priority.getDisplayValue(),
})
}
return incidents
},
type: "IncidentUtils", }
Client Callable Script Include (ES5)
// Extends AbstractAjaxProcessor for GlideAjax calls var IncidentAjax = Class.create() IncidentAjax.prototype = Object.extendsObject(AbstractAjaxProcessor, { /**
- Get incident details - callable from client
- Client calls: new GlideAjax('IncidentAjax').addParam('sysparm_name', 'getIncidentDetails') */ getIncidentDetails: function () { var incidentId = this.getParameter("sysparm_incident_id") var result = {}
var gr = new GlideRecord("incident")
if (gr.get(incidentId)) {
result.success = true
result.number = gr.getValue("number")
result.short_description = gr.getValue("short_description")
result.state = gr.state.getDisplayValue()
result.priority = gr.priority.getDisplayValue()
result.assigned_to = gr.assigned_to.getDisplayValue()
result.assignment_group = gr.assignment_group.getDisplayValue()
} else {
result.success = false
result.message = "Incident not found"
}
return JSON.stringify(result)
},
/**
- Search incidents by keyword */ searchIncidents: function () { var keyword = this.getParameter("sysparm_keyword") var limit = parseInt(this.getParameter("sysparm_limit"), 10) || 10 var incidents = []
var gr = new GlideRecord("incident")
gr.addQuery("short_description", "CONTAINS", keyword)
gr.addOrCondition("description", "CONTAINS", keyword)
gr.addQuery("active", true)
gr.setLimit(limit)
gr.orderByDesc("opened_at")
gr.query()
while (gr.next()) {
incidents.push({
sys_id: gr.getUniqueValue(),
number: gr.getValue("number"),
short_description: gr.getValue("short_description"),
})
}
return JSON.stringify(incidents)
},
/**
- Check if user can update incident */ canUserUpdate: function () { var incidentId = this.getParameter("sysparm_incident_id") var userId = gs.getUserID()
var gr = new GlideRecord("incident")
if (gr.get(incidentId)) {
// Check if user is assigned or in assignment group
var canUpdate =
gr.getValue("assigned_to") === userId || this._isUserInGroup(userId, gr.getValue("assignment_group"))
return JSON.stringify({ canUpdate: canUpdate })
}
return JSON.stringify({ canUpdate: false })
},
_isUserInGroup: function (userId, groupId) { var member = new GlideRecord("sys_user_grmember") member.addQuery("user", userId) member.addQuery("group", groupId) member.query() return member.hasNext() },
type: "IncidentAjax", })
Client-Side GlideAjax Call (ES5)
// Client script calling Script Include function getIncidentDetails(incidentSysId, callback) { var ga = new GlideAjax("IncidentAjax") ga.addParam("sysparm_name", "getIncidentDetails") ga.addParam("sysparm_incident_id", incidentSysId) ga.getXMLAnswer(function (answer) { var result = JSON.parse(answer) callback(result) }) }
// Usage in client script getIncidentDetails(g_form.getUniqueValue(), function (incident) { if (incident.success) { g_form.addInfoMessage("Incident: " + incident.number) } else { g_form.addErrorMessage(incident.message) } })
Inheritance Pattern (ES5)
// Base class var TaskUtils = Class.create() TaskUtils.prototype = { initialize: function (tableName) { this.tableName = tableName || "task" },
getByState: function (state) { var records = [] var gr = new GlideRecord(this.tableName) gr.addQuery("state", state) gr.query() while (gr.next()) { records.push(this._toObject(gr)) } return records },
_toObject: function (gr) { return { sys_id: gr.getUniqueValue(), number: gr.getValue("number"), short_description: gr.getValue("short_description"), state: gr.getValue("state"), } },
type: "TaskUtils", }
// Derived class var IncidentUtilsExtended = Class.create() IncidentUtilsExtended.prototype = Object.extendsObject(TaskUtils, { initialize: function () { TaskUtils.prototype.initialize.call(this, "incident") },
getP1Incidents: function () { var incidents = [] var gr = new GlideRecord("incident") gr.addQuery("priority", 1) gr.addQuery("active", true) gr.query() while (gr.next()) { var obj = this._toObject(gr) obj.caller = gr.caller_id.getDisplayValue() incidents.push(obj) } return incidents },
type: "IncidentUtilsExtended", })
Scoped Script Include (ES5)
// In scoped application: x_myapp var MyAppUtils = Class.create() MyAppUtils.prototype = { initialize: function () { this.APP_SCOPE = "x_myapp" },
/**
- Get application property
- @param {string} name - Property name (without scope prefix) */ getAppProperty: function (name) { return gs.getProperty(this.APP_SCOPE + "." + name) },
/**
- Log with application prefix */ log: function (message, source) { gs.info("[" + this.APP_SCOPE + "][" + (source || "MyAppUtils") + "] " + message) },
/**
- Access cross-scope table safely */ getGlobalUser: function (userId) { var gr = new GlideRecord("sys_user") if (gr.get(userId)) { return { name: gr.getValue("name"), email: gr.getValue("email"), } } return null },
type: "MyAppUtils", }
MCP Tool Integration
Available Script Include Tools
Tool Purpose
snow_create_script_include
Create new Script Include
snow_find_artifact
Find existing Script Includes
snow_edit_artifact
Modify Script Include code
snow_execute_script_with_output
Test Script Include
Example Workflow
// 1. Create Script Include await snow_create_script_include({ name: "IncidentUtils", script: "/* Script Include code */", client_callable: false, description: "Incident utility functions", })
// 2. Test the Script Include
await snow_execute_script_with_output({
script: var utils = new IncidentUtils(); var incident = utils.getByNumber('INC0010001'); gs.info('Found: ' + (incident ? incident.number : 'null')); ,
})
Best Practices
-
Single Responsibility - One class, one purpose
-
Meaningful Names - IncidentUtils not Utils
-
Document Methods - JSDoc comments
-
Error Handling - Try-catch with logging
-
Private Methods - Prefix with underscore
-
No Side Effects - Initialization should not modify data
-
Testable - Write methods that can be unit tested
-
ES5 Only - No const, let, arrow functions, template literals