Servicenow x NodeJS Bridge Part 1
This is the first post in the series about connecting the Servicenow platform to the nodeJS ecosystem by creating a bridge, to allow you to use more modern packages and extend the tools beyond the platforms reach
Did you ever wanted to write ES6 code or just simply use a node module while working with Servicenow? Now you can make your dreams come true!
Code Editor
On the platform, so you can write your own scripts, you mostly use the integrated code editor, which uses CodeMirror. Codemirror is quite popular amongst these web based code editors, so the choice of software is not bad, but Servicenow imposed some limitations to the editor.
On the platform, you are not allowed to write scripts with the keywords like const
, let
, write arrow functions, etc. There are some weird archaic restrictions, which prevent you from writing quick and easily readable code. You may ask why do they have such things?
Why?
The reason is actually quite simple, I guess. The platform - as probably many enterprise platforms out there - is written in Java. Due to the nature of the platform, back in the times at the beginning, at some point, they did choose to use Rhino.
Rhino
Rhino as their webpage says:
”Rhino is an open-source implementation of JavaScript written entirely in Java.”
It does provide you with a way to script customizations on the platform in javascript. Sadly this comes with its downsides. I am not sure which Rhino version is deployed at the moment, but I am pretty sure that it is a very old one. You can’t run ES6+ style code there in any way. Some of the internal functions are also disabled due to security or other reasons.
The limits may become frustrating at times. Although one would understand the reason behind blocking the ES6 style code running in Rhino because that is not fully supported anyways, the same blocking is also imposed on Client scripts too.
I know that we (in a generic webapp development, by using webpack, parcel, rollup etc.) are still precompiling ES6 style code to browser compatible format to support more browsers, but some of these functions or patterns could be now, while I am writing this post easily used in production with most of the modern browsers available.
If you don’t believe me, see for yourself, this page describes which of the modern features can be used while running Rhino. It is mostly like red river, although some of these are now with the latest releases from late 2018 or 2019 possible, there is still a stunning 65%+ not available (as of writing this post). I am not blaming the devs, I am sure that it is not an easy task to implement this properly in Rhino, with backward compatibility in mind and also many more difficulties which could arise.
Writing scripts on the Servicenow platform
Writing scripts on the platform can be dreadful. The code editor has little knowledge about your code (I know, it’s an editor, not a fully-fledged IDE). The web editor complains about you not putting an ;
(missing semicolon) at the end of a line (this is not even required in vanilla JS at all, so I am not sure of the reason), but does not complain if you call an undefined function.
There are many internal API’s closed down for outside inspection, only existing as a Java class on the respective instances. If you would like to make some customisations to this, then you are out of luck.
You can use these Java api’s like GlideSystem
, GlideRecord
or many more, but you can never be sure about the resulting output. You may think that if you have a String
type field in the table you have just created, then querying the table would return the same type of result back. You’ve never been more wrong in your life.
Sometimes you are getting back a Java String, which is not the same as a Javascript string. Also some cases may get you a Java object as a result, sometimes not. Have you ever worked with Java arrays in javascript? On Servicenow, you have a big chance to stumble upon these.
This type confusions lead to many error prone scripting and bad results. You can of course convert these to “javascript types” but this leads to boilerplate code, which the platform could handle instead of the user who is writing the customizations.
You must use methods like someVariable + ""
or someVariable.toString()
to ensure you get a string back. You would say that these aforementioned methods are the same, well, they may be or they may not be, you are never 100% sure until you try.
I know, it may sound like some hate, but this is just my very personal opinion and experience during these years working with the platform.
The problem
So due to the things described before and also other factors, I was growing more and more tired of the platform and the limitations which it imposes on some areas. That is why I was thinking of a way to provide a flexible solution to the issues at hand. That is where the idea was born out of this confusion, which we will from now on, call “Servicenow x NodeJS Bridge”.
I am really sorry for the lengthy intro. I really wanted you to have the full picture of the reasons and actions behind the scenes that led me to this.
The Bridge
The issue as described was, that we have a lot of limitations which sometimes prevent us to write good code. You are not able to use npm modules for some of your scripts. Sometimes you can copy paste them together as a client script. For this to work, you need a browser open, you can’t run it on the server side.
Most modules have distribution files, precompiled. These come mostly in a minified versions. If you paste these contents to a “UI script” then it may happen that you get stuck with a frozen browser tab.
These problems lead us to many “hacking” on the platform. Really, we are reinventing the wheel sometimes.
Example case
Let’s just go with an real-life example.
You have a client, let’s call the company Sampler. Sampler contacted you, that they would like to have a way to generate a custom made PDF which they can then attach to some incidents on the platform.
You have some OOTB (out of the box) options, but they are mostly limited. You can generate a PDF from form fields on a form view or rather a simple list of fields and their values. No formatting options at hand. This is nice, but sometimes not enough.
Customers would like to customize the PDF sometimes, like put their own logo somewhere or simply have bigger flexibility.
We could use many existing solutions, but those can only work in the browser. The limitation forces us to the fact, that we must have an active browser open and we need to actually click on some user actions and generate the PDF manually. This happens by using the well-known “Print to PDF” or “Save to PDF” to get an actual PDF of the HTML generated by the platform.
One example of the state of the PDF generation can be found here and of course you can find many on the community. 1
Servicenow x NodeJS Bridge
And now we finally arrived at the main attraction of this whole post. The idea was to improve the state of affairs on the platform. I wanted to make this happen, by connecting one of the most well-known and powerful platforms out there to help us do more by still using Servicenow, but also using the modern tools and libraries available to us already.
The task was simple, provide a way to run modern scripts without the need of your browser (you, actually opening a webpage and interact) to be open.
Technical details
I did create a hosted instance of a NodeJS sandbox (let’s call this node vm later on) with a REST API and then connected this through the API to the Servicenow Instance.
The node vm listens on a simple REST API on a host:port
. To make this easy, I have a docker-compose file available for you where you just need to do a simple docker-compose up
to run the service. I am also putting this behind a reverse proxy which you can easily configure.
You will need to host the instance yourself. I am not providing a public demo at this time. You will find out that the setup is easy and straightforward. Don’t worry, if you will get stuck with something, just open an issue. Me and the community is here to help :).
I also made it easy to host this instance at any customer internally if required. You just spin up the container and go on.
After downloading the files from the github repository. You need to manually install all npm modules and packages you will be using. I am just providing a base sample which lets you run the vm itself.
Let’s make this more clear. For example, if you would like to use the faker
(
Faker.js on github) package, then you would need to execute the following commands:
➜ cd snc-node-bridge
➜ yarn add faker # or npm install faker --save`
You need to cd to the folder where you have the package.json and then install the package first, after this, run your container. Feel free to ask questions on issues for the repository found at the end of the post. Also, before posting, please review the Wiki pages, maybe your question has already an answer there.
Scoped app (Servicenow side)
There are two repositories under the github organisation page. One repository is for the Scoped app. The scoped app must be loaded to the Servicenow instance. This scoped app allows you to write custom scripts. These scripts can be run in the node vm afterwards.
Due to the limitations of the platform and the disabled ES6 properties, I had to replace the builtin editor with a custom made one.
I tried to find a reliable way to configure the Servicenow builtin editor to suit my needs, I was out of luck. The lack of configurability was sad. There was also no documentation about this. I guess this was poised to be “use it only”. I also wanted to avoid hacking the editor because that would lead to future problems.
The decision was not made lightly, but if someone is determined in their goal, then nearly everything is possible.
I choose to replace the builtin code editor. In a paradox, I am using Codemirror too. I’ve built a simple react component for my purpose. This editor is also not much configurable at this moment, but I am open to suggestions. The code is loaded from a CDN I am using.
I tried to make this work on the platform, to load the scripts from the instance, but sadly this was not possible. I pasted the minified script in a “UI Script” entry, like recommended by Servicenow (if one wants to use external libraries). In turn, the whole browser froze off. My assumption is that it is due to the Syntax highlighting. The editor instance tried to highlight the minified script. This resulted in a frozen off tab. I concluded that this was not maintainable long-term.
Loading the cdn scripts affects the development part only. You would not need the code editor component on production instances. If in concern due to the external scripts, you are free to firewall this off on production.
I wired the custom editor and the g_form together. On the form load, I am getting the value from the script field and passing it to the react component.
The script field is a simple text field, hidden on the form. We are reacting to onchange on the custom editor and updating the hidden field value to provide a seamless experience. You are simply able to save the form like you would normally. No hassle, no problems. A seamless experience for your everyday use.
Data bootstrap
There is also a Data bootstrap
field for the bridge scripts. The purpose of this is to provide a way to send some data along the request with the script to the node vm. You can then use this data in your Bridge Script with the builtin sandbox function _getData()
. You can find examples in the Wiki about this.
Flow
The flow is simple. You write your script. Data bootstrap is not required, but you will probably need this. You can also use the Servicenow REST API. This data bootstrap script is evaluated on the Servicenow instance. The resulting object/array is sent along the request to the node vm.
You can run the script with the “Run Script” UI Action on the Bridge Script. The UI Action calls the Utils Script Include. You can call this method from anywhere in your other scripts.
Since we can now also write async functions, I had to think of a way to send data back. For this purpose, I created a so-called postback function
.
These postback functions need to be part of the original script which we are sending (for the time being). The bridge scripts can be async, so there is no point in waiting for an answer. Some tasks may take a few seconds or the others a couple more.
Call the postback function somewhere at the end of your bridge script. For example, if you would have some async functions, you would call this somewhere after you resolve all the promises or have awaited all the results. I created an internal function _getLogID()
. This returns the sys_id
of the log entry. This log entry was created after you clicked “Run script”. This sys_id was already sent along the request initially. Results are at the moment sent back to the Execution log entry which was created while you were running the script. It is recommended to send back the results to the instance in an organized manner. The best way would be to use the log entry created in relation to the run. Since you control the postback function, you can do whatever you want. You want to use the Servicenow REST API for something else? Feel free! Also, please findmore info on the Wiki pages.
Final note
Thanks for reading through the post. I intended this to tell you about my personal experience and thoughts about Servicenow. Why and how I was led to create this project. And of course there is also a duty from my side to the open source community. I learned a lot through the years and I would like to contribute back with something useful. Something meaningful and also helpful for others.
With this tool, I would like to ease the development of new interesting tools on the Servicenow platform and well, we will see where this leads us.
If you have any questions or interesting ideas, please submit them on the github issues pages for the respective repositories and we can have a discussion. I am open to suggestions and constructive criticism is always welcome.
Repositories:
If you are interested, please put a star on the repos or follow myself to get updates about the projects. Also you can occasionally follow my blog or linkedin for more updates about this or any of my other projects.
This is the first in a series of post about the bridge. More is coming, stay tuned! :)
Disclaimer: The statements and opinions written in this post, may not reflect the view of the company I am currently employed at. These are my personal statements and observations only. Please consider them as such. Thanks!