- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
07-23-2019 04:20 PM
Question
What is the best way to Dynamically create a Requested Item (sc_req_item) from an external source (outside of ServiceNow).
The slightly complexity is that the person performing the Approval must be variable (i.e. specified externally in the REST call).
Project Background and Requirements
I am working to Automatic Fulfilment. My customer is the “OpenShift” team who are involved in Containers etc.
There is a requirement from Security that Access to each OpenShift project is Approved every 6 months.
So the OpenShift team want to do this automatically every month – for every non-prod and prod project.
In Non-prod now I think there are over 1,000 projects.
For each Approval request, the approval would be done by a different manager, the manager of the Openshift project.
I guess we could automate this by email, but it is tracked better in ServiceNow – and also if the Manager of the team
“Rejects” – it would be nice to route the RITM to the Security team for action – since it would be them who would then
deny users access to the OpenShift project – by altering an AD Group (I need to confirm this).
Implementation
I have implemented this using a new table called the MessageQueue (I just read about SN Processors – this also has potential).
I have written a business rule which triggers on an incoming message; the OpenShift team use Python and the REST/API to write
To the MessageQueue.
I have a simple business rule which triggers on the incoming message and then calls a slightly more complex Script Include.
My custom ScriptInclude uses the inbuilt SN “Cart” ScriptInclude to dynamically create a RITM from a predefined Catalogue Item. (sc_cat_item).
My Script Include also has a simple function to add the Approval for the manager. (see code below). I can’t define the Approval in the
Catalog Item (sc_cat_item) – because the manager is different for every project.
However, when I add the approval, the sc_req_item has already been automatically approved and moved into a closed stage
(because there are no tasks and no approvals). I would normally fix this by setting ritm.setWorkFlow(false);
However, I am using the Cart ScriptInclude and can’t (or don’t want to modify SN out-of-the-box-code).
So I have started to investigate options:
- Simply Copy the Cart Script Include and create my own – and insert setWorkFlow(false); where appropriate.
But I hate to duplicate code (no matter how short it is) Just seams wrong and less supportable. - I also investigating creating a sc_req_item dynamically without any predefined sc_cat_item. This would be really nice.
But I started getting confused about adding variables and the purposes of the tables: sc_item_option] and sc_item_option_mtom].
- I could reset the RITM and Request stage back to a Not Approved (i.e. requested) state.
However, this is more and more database updates and just seams inelegant.
- I started looking at other APIs. Such as the the CartJS API or the CatItem. Again – a bit confusing.
and I don’t think these options would necessarily solve the problem
– since I suspect these APIS don’t include setWorkFlow(false);
- I could just use the Standard ServiceCatalog REST API – rather than the Table REST API and the MessageQueue.
I also just read about “Processors”. Cool. However, I think they only work for URL Queries (i.e. GETs not POSTs). - Define a fixed approver on the sc_cat_item template. Then dynamically change the name of the approver
on the 'sysapproval_approver'record immediately after the sc_req_item has been instantiated.
However, It would be nice to create things correctly in the first place – without this work-around. - Define the Catalogue Item with a Workflow that reads the name of the approver from the associated MessageQueue record,
and sets the approver on the sc_req_item dynamically somehow. I have not dine this before - but probably possible.
This is not a very flexible solution - since I have to create custom workflow for any req_item instantiated externally
via the REST API. Ideally, I would like to make it possible to instantiate ANY cat item via REST.
Conclusion (sort of)
I am beginning to doubt myself and this implementation of the MessageQueue.
Maybe I should have told customers to just use the Service Catalogue REST API and leave all these decisions to my customers.
However, I suspect this would just move the code from within ServiceNow to Outside of ServiceNow –
from JavaScript to Python. It is also a bit lazy and isn't customer focused. Of the options above, I suppose option 1 is the best.
An elegant solution looks far away. There are almost too many options
- and I find the implementation of sc_item_option_mtom be be highly confusing; I am afraid to touch it directly.
// ###################################################################################################
// Add an Approval for the RITM - in the sc_cat_item_app_user
function addApproval(ritm, user_sys_id) {
debug_text += "\n ----- addApproval -----";
debug_text += "\n user_sys_id = " + user_sys_id;
var approval_gr = new GlideRecord('sysapproval_approver');
approval_gr.initialize();
approval_gr.approver = user_sys_id;
approval_gr.state = 'requested';
approval_gr.sysapproval = ritm.sys_id;
var approval_id = approval_gr.insert();
debug_text += "\n addApproval: approval_id = " + approval_id;
return approval_id;
}
Solved! Go to Solution.
- Labels:
-
Integrations
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-18-2019 07:24 PM
Scripted REST API
The Scripted REST/API contains an Service Catalog API. If you open up some of the items, you can see that it is using a library called sn_sc.CartJS. I think this is the best one to use. If you want to see sample code and understand what ServiceNow itself uses to implemented its REST APIs, then look at the Scripted EST API Examples. There are about 70 examples.
This is best API - and I successfully uses this API to create Catalog Items.
You can also look at other Scripted Test API examples - for example - there is one for managing Changes.
Going forward, I will try an take advantage of the Scripted REST API and the underlying code (I am already using the CartJS). Defining a Custom ANZ REST/API seams to make sense from the point of view of good OOP principles such as:
- defining a limited Interface
- hiding the Implementation.
I will try and use Scripted REST APIs going forward - and not reinvent the wheel.
Approval Defined via Variable on Service Catalogue
In order to add an approval to my Service Catalogue Item, using the REST/API, I first created a Service Request and populated a variable with the name of the Group who I wanted to do the approval. I then used a workflow to read the variable and add the approval.I was unsure if this would work due to timing issues (see sequence below), but my fears were unfounded. It works fine.
Sequence of Execution
In terms of the Sequence of when things are executed, I am still a bit unclear - however it might to be as follows:
If you insert a record into a table using the GlideRecord insert() method - then all of the following actions appear to occur synchronously within one thread (but again I am still really not certain):
- First the Workflow for the type of table is executed
- Next the Before Insert Bus Rule is executed.
- The Record is Inserted
- The After insert rule is excuted.
Questions:
- The documentation is clear about the Sequence for Business rules - but it is not clear if the Workflows are triggered first? From experience, I think the Workflow is triggered first.
- If there is also a Workflow or a Bus Rule defined for a Base Table and an Extended Table - presumably they both execute? Which one executes first? Are they executed according the the Order field? or Base Table First?
- What about the Scope of JavaScript functions and Variables within this thread? If you have two functions with the same name does the second one redefine the first? Is that why there is an emphasis on anonymous functions in the sample code within SN
- Javascript in SN is executed within Java somehow. It would ne nice to know when the JavaScript is compiled and when the thread finishes - so that I could understand scope a bit better.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
07-23-2019 06:58 PM
From my understanding of the requirements I have the following suggestion:
Why don't you have a variable in your catalog item which could be used for creating approvals in the workflow. You don't need to create the approvals after the catalog item has been submitted.
Let's say you create a manager variable on the catalog item. You can then create a workflow for the approval and use the value present in the manager field (or any other field) to generate the approval for that person.
You can use the Cart API to set the variables when you are creating the RITM using the catalog item. So, the idea is using a generic catalog item with the details that are not gonna change, and use that template to generate the RITM; pass the manager variable, so that it becomes dynamic and gets triggered by your REST Call.
Hope this helps!
Cheers,
Manish
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
07-24-2019 12:01 AM
Sounds Like a Good Plan. I will investigate. I am slightly concerned about the timing. I am a bit unfamiliar about when the Workflow is kicked off; I think it may be initiated by a Before insert Business rule on the RITM. In which ase the approval will get built before I have a chance to populate the variable that you mentioned; remember, I need to set it via the REST API. However, it is a definite a possibility - and I might be concerned about nothing. so thank you for contributing. I will try your idea.
After careful thought all morning, I am also looking at Inheriting the Cart class and overriding the addItem() method - so that I can add the statement: gr.setWorkFlow(false); See below. Inheritance in JavaScript is a bit different to what I am used to. I have been reading about Javascript scope, Prototypes, __proto__ and the difference between call() and apply().
-----------------------------------------------------------------------------------------------------------
ANZCartBuilder.prototype = Object.extendsObject(Cart, { initialize: function(cartName, userID) { // Call the constructor of the Base Class Cart.prototype.initialize.call(this, cartName, userID); this.debugText = "ADC: ANZCart: Initialize"; }, printDebug: function() { gs.log(this.debugText); }, // ################################################################################################### addItem: function(catItemID, quantity) { // This function overrides the function in the Base class 'Cart' and adds: setWorkFlow(false); this.debugText += "\n ----- addItem -----"; var gr = new GlideRecord('sc_cart_item'); gr.initialize(); // Stop all Business Rules and Workflows from triggering. gr.setWorkFlow(false); gr.cart = this.cart.sys_id; gr.cat_item = catItemID; gr.quantity = quantity; var cartItemID = gr.insert(); this.prepVariables(catItemID, cartItemID); this.cartItem = gr; return cartItemID; },
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
07-24-2019 01:30 PM
I guess Manish's response depends on how gr.insert(); has been implemented:
- Does the gr.insert() method trigger and run all Before and After Business Rules before continuing execution at the next line in the current script; or...
- Does the gr.insert() method just create a pending database insertion and the Before and After Rules are only run after the current script has completed.
If you look at the documentation (see links below), it is not entirely clear. I am assuming that 1. is true. Does anyone know for sure? Maybe I should open another question.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-18-2019 07:24 PM
Scripted REST API
The Scripted REST/API contains an Service Catalog API. If you open up some of the items, you can see that it is using a library called sn_sc.CartJS. I think this is the best one to use. If you want to see sample code and understand what ServiceNow itself uses to implemented its REST APIs, then look at the Scripted EST API Examples. There are about 70 examples.
This is best API - and I successfully uses this API to create Catalog Items.
You can also look at other Scripted Test API examples - for example - there is one for managing Changes.
Going forward, I will try an take advantage of the Scripted REST API and the underlying code (I am already using the CartJS). Defining a Custom ANZ REST/API seams to make sense from the point of view of good OOP principles such as:
- defining a limited Interface
- hiding the Implementation.
I will try and use Scripted REST APIs going forward - and not reinvent the wheel.
Approval Defined via Variable on Service Catalogue
In order to add an approval to my Service Catalogue Item, using the REST/API, I first created a Service Request and populated a variable with the name of the Group who I wanted to do the approval. I then used a workflow to read the variable and add the approval.I was unsure if this would work due to timing issues (see sequence below), but my fears were unfounded. It works fine.
Sequence of Execution
In terms of the Sequence of when things are executed, I am still a bit unclear - however it might to be as follows:
If you insert a record into a table using the GlideRecord insert() method - then all of the following actions appear to occur synchronously within one thread (but again I am still really not certain):
- First the Workflow for the type of table is executed
- Next the Before Insert Bus Rule is executed.
- The Record is Inserted
- The After insert rule is excuted.
Questions:
- The documentation is clear about the Sequence for Business rules - but it is not clear if the Workflows are triggered first? From experience, I think the Workflow is triggered first.
- If there is also a Workflow or a Bus Rule defined for a Base Table and an Extended Table - presumably they both execute? Which one executes first? Are they executed according the the Order field? or Base Table First?
- What about the Scope of JavaScript functions and Variables within this thread? If you have two functions with the same name does the second one redefine the first? Is that why there is an emphasis on anonymous functions in the sample code within SN
- Javascript in SN is executed within Java somehow. It would ne nice to know when the JavaScript is compiled and when the thread finishes - so that I could understand scope a bit better.