Replacing Inaccessible APIs with Utility Script Includes in Scoped Applications - ben-vargas/servicenow-wiki GitHub Wiki
This article explains how to overcome limitations in scoped applications by creating reusable utility Script Includes. Specifically, it demonstrates how to replace the inaccessible gs.dateGenerate()
method with a custom function that achieves the same result, while adhering to scoped application restrictions. This approach promotes reusable code and maintainability in your scoped applications.
The Challenge
Scoped applications in ServiceNow have restrictions on the APIs they can access. This can be an issue when a global scope API is needed. A common example of this is the gs.dateGenerate()
method, which is not directly available within scoped applications. This method allows for easy creation of dates in a specific format. When building scoped applications, this limitation can require using alternative methods to achieve the same results.
The Solution
The solution is to create a utility Script Include that contains a replacement for the inaccessible method. This approach offers:
- Reusability: Utility Script Includes can be shared and used across multiple scripts within the scoped application and by other scoped applications if configured appropriately.
- Maintainability: Centralizing code in a Script Include promotes easier updates and maintenance.
- Scope Compliance: The utility code will work within the context of a scoped application, adhering to scope restrictions.
- Flexibility: By creating your own custom logic, you can tailor the utility to your specific needs.
Creating a Utility Script Include:
-
Create a New Script Include:
- Navigate to System Definition > Script Includes.
- Create a new Script Include with the following values:
- Name:
Tools
- Client callable:
Checked
(optional but useful for some scenarios) - Accessible from:
All application scopes
(if you intend to share this with other apps) - Script: Replace the default code with the code below.
- Name:
-
Script Include Code:
var Tools = {}; Tools.dateGenerate = function(date, range) { if (!range) range = '12:00:00'; var gdt = new GlideDateTime(); if (range.equals("start")) gdt.setDisplayValueInternal(date + " 00:00:00"); else if (range.equals("end")) gdt.setDisplayValueInternal(date + " 23:59:59"); else gdt.setDisplayValueInternal(date + " " + range); return gdt; }; Tools.fixFilter = function(filterString) { if (!filterString) return filterString; //lets ensure we are working on a string: filterString = filterString + ''; //fix dateGenerate var dateGenerateRegex = /gs\.dateGenerate/gm; var ourDateFunction = "Tools.dateGenerate"; return filterString.replace(dateGenerateRegex, ourDateFunction); };
Explanation:
var Tools = {};
: This defines an empty object. This is a best practice for utility classes as it helps to prevent unnecessary creation of new class instances.Tools.dateGenerate = function(date, range) { ... }
: This creates a customdateGenerate
function, designed to behave like the globalgs.dateGenerate
.- It takes a
date
andrange
parameter. Therange
parameter defaults to 12:00:00 if it's missing. - It creates a
GlideDateTime
object and usessetDisplayValueInternal
to parse the date string and return it.
- It takes a
Tools.fixFilter = function(filterString) { ... }
: This creates a customfixFilter
function that will replace instances of thegs.dateGenerate
function with the customTools.dateGenerate
function.- This will take a filter string and replace all instances of
gs.dateGenerate
withTools.dateGenerate
.
- This will take a filter string and replace all instances of
Using the Utility Script Include
-
Access from within Scoped Applications
- Within the scoped application, you can call the functions on the
Tools
object directly, usingTools.dateGenerate
andTools.fixFilter
methods.
- Within the scoped application, you can call the functions on the
-
Using with Encoded Queries:
- Encoded queries frequently use the
gs.dateGenerate
method. - To use your custom
Tools.dateGenerate
in an encoded query, you can use theTools.fixFilter
method to replace any instances ofgs.dateGenerate
with the custom method. - Example:
var enq = "opened_atBETWEENjavascript:gs.dateGenerate('2024-01-01','12:00:00')@javascript:gs.dateGenerate('2024-12-31','12:00:00')"; var inc = new GlideRecord('incident'); inc.addEncodedQuery(Tools.fixFilter(enq)); inc.query(); gs.info("Incidents matching query: " + inc.getRowCount());
- Encoded queries frequently use the
-
Access from other scoped applications
- If the Script Include is configured to be accessible to other application scopes, other scoped applications can take advantage of the utility, for example:
var enq = "opened_atBETWEENjavascript:gs.dateGenerate('2024-01-01','12:00:00')@javascript:gs.dateGenerate('2024-12-31','12:00:00')"; var inc = new GlideRecord('incident'); var Tools = sn_custom_app.Tools; //Replace sn_custom_app with the scope that this script include exists in. inc.addEncodedQuery(Tools.fixFilter(enq)); inc.query(); gs.info("Incidents matching query: " + inc.getRowCount());
- If the Script Include is configured to be accessible to other application scopes, other scoped applications can take advantage of the utility, for example:
Best Practices
- Utility Script Includes: Develop utility Script Includes to centralize commonly used functions.
- Naming Conventions: Use descriptive names for your Script Includes and their methods.
- Scope Control: Only expose your utility includes to the application scopes that need them, to prevent unintended access.
- Comments: Add comments to your code to explain the purpose and logic.
- Testing: Always test utility classes thoroughly in a development environment before deploying to production.
- Error Handling: Consider adding error handling to your utility methods to catch unexpected input or data issues.
- Modularity: Use a modular design pattern, keeping each utility focused and limited to a specific task. This will improve maintainability and allow other developers to quickly understand the core purpose of the method.
- Accessibility: When making your utility classes accessible to other scopes, make sure that the public API is stable and you will not be changing the core function without notifying your users.
Why This Approach is Valuable
- Overcomes Scope Limitations: It provides an alternative for inaccessible APIs within scoped applications.
- Promotes Reusability: The custom code can be easily reused by any other scripts in the application.
- Improves Maintainability: Encapsulates logic, making your application easier to update and maintain.
- Encapsulation: Protects the internal state of your scripts, preventing accidental overwrites.
Conclusion
This article demonstrates how to use a utility Script Include to overcome the restrictions of scoped applications by creating a replacement for the global gs.dateGenerate()
method. By adopting this approach, you can build robust and flexible scoped applications while adhering to platform constraints. Remember to test thoroughly in a non-production instance before deploying to production.