sabell2012
Mega Sage

NOTE: MY POSTINGS REFLECT MY OWN VIEWS AND DO NOT NECESSARILY REPRESENT THE VIEWS OF MY EMPLOYER, ACCENTURE.

 

DIFFICULTY LEVEL: INTERMEDIATE
Assumes a good knowledge and/or familiarity of REST web services and Scripting in ServiceNow. Assumes having taken the class SSNF and has good intermediate level of knowledge and/or familiarity with Scripting in ServiceNow. 


Some time ago I had to create a REST Web Message to retrieve information from a server. It occurred to me that there really had not been many examples written on this for ServiceNow. At least from the code perspective. So I thought I would share. This really isn't that complicated, and you should be able to glean what you need from the ServiceNow documentation, but I thought I would present a working example to play with anyway.

 

In this example we will be using a test REST web service site called: 'cat-facts'. This will return a success string (true/false), and from 1 to any number we specify; of facts about cats.

 

The idea here is to retrieve data from a REST Web Service and then parse the results into a JSON object for further use.

 

What is needed:

 

  1. Web Service end-point. This will be: 
    1. https://catfact.ninja/facts?limit=<<some number>>
    2. If the number is not provided it is automatically assumed to be 10.
  2. ServiceNow REST Message
  3. Fix Script to run our test code and parse the results

 


Lab 1.1: Creating the Rest Message

 

  1. Navigate to System Web Services > REST Message.
  2. Click on the New button to create a new REST Message.
  3. Fill in the form with the following:
    1. Name: CatFacts
    2. Accessible from: All application scopes
    3. Description: Retrieve facts about cats!
    4. Endpoint: https://catfact.ninja/facts 
    5. Authentication type: No authentication
    6. Right-click on the form header and choose Save. This will auto-generate four HTTP methods (get, put, post, delete).   We will only be using "get" for the purposes of this article.

 

sabell2012_0-1703804168873.png

 

4. In the HTTP Methods related list click on the "Default GET" method.

5. Change the Endpoint to: https://catfact.ninja/facts?limit=${limit}

6. Right-click on the form header, and Save your work.

7. Scroll to the bottom of the form and from the Variable Substitution related list click the New button.

8. Fill out the form with the following:

a. Name: limit

b. Escape type: No escaping

c. Test Value: 5      <- we will be pulling back five facts about cats.

d. Click Submit to save the variable.

 

sabell2012_3-1703804651276.png

 

9. Scroll down to the bottom of the Method form, and choose the "Test" link under the related links.  

This will execute the REST Message with the number value of 5.  

10. You will get a 200 result (success), and five facts about cats!

 

sabell2012_4-1703804734431.png

 

Our REST Message is now ready to be consumed - a fancy programmer term meaning: "used".

 

 

Lab 1.2: Fix Script to Run Consume the REST Message

 

So now comes the cool stuff. We will be creating code to execute the REST Message, and then convert the response to a JSON object so that we can actually make some use of it.

 

  1. Navigate to Fix Scripts.
  2. Click the New button.
  3. Fill out the form with the following:
    1. Name: Cat Facts
    2. Description: Test script to consume the CatFacts REST Message
    3. Script:

 

var location = 'FS: CatFacts';
var webService = 'CatFacts';
var command = 'Default GET'; // case sensitive
var limit = 5;
var message = gs.getMessage('---> [{0}]\n', [location]);

try {
	var restMessage = new sn_ws.RESTMessageV2(webService, command);
	restMessage.setStringParameter('limit', parseInt(limit));
	var response = restMessage.execute(); // REST return
	var httpStatus = response.getStatusCode(); // response status code

	var responseBody = response.getBody(); // stringified JSON returned info
	var jsonBody = JSON.parse(responseBody); // turn it into a true JSON object

	// Now we can begin using the response
	message += gs.getMessage('\tResponseBody: {0}\n', [responseBody]);

	var facts = jsonBody.data;
	var success = httpStatus == 200;

	message += gs.getMessage('\tfacts.length: {0}\n', [facts]);
	message += gs.getMessage('\tjsonBody.success: {0}\n', [success]);
	message += 'Facts:\n';
	if (success) {
		for (var i = 0; i < facts.length; i++) {
			message += gs.getMessage('\t[{0}]: {1}\n', [i, facts[i].fact]);
		}
	}
}
catch(err) {
	gs.error('---> ERROR: ' + err);
}
gs.info(message);

 

4. Right-click on the form header and Save your work.

 

sabell2012_8-1703805674456.png

 

5. Navigate to System Logs > System Log > All and filter Message for --->

 

sabell2012_7-1703805632061.png


And there you have it! In this article I demonstrated:

 

  1. How to create a REST Message
  2. How to add a variable to the REST Message method
  3. How to test a REST Message method
  4. How to call a REST Message from a script
  5. How to use a variable in a REST Message from a script
  6. How to parse the returned results into JSON from the REST Message
  7. How to consume (a.k.a. use) the JSON results

 

Enjoy!

Steven Bell.

 

If you find this article helps you, don't forget to log in and mark it as "Helpful"!

 

sabell2012_0-1703794648636.png


Originally published on: 09-06-2016 01:50 AM

I updated the code, fixed broken links, and brought the article into alignment with my new formatting standard

Comments
Kilo Contributor

Hi Steve,



When I ran the fix script in my Dev instance I received following error. Can you help me with this




Evaluator: java.util.NoSuchElementException       Caused by error in Script Include: 'JSON' at line 145           142:         },         143:           144:         decode: function(source) { ==> 145:                 return new SNC.JSONParse().decode(source);         146:         },         147:           148:         type: "JSON"   java.util.LinkedList.remove(LinkedList.java:788) java.util.LinkedList.removeFirst(LinkedList.java:134) java.util.LinkedList.pop(LinkedList.java:601) com.glide.script.JSONParse.handleObjectEnd(JSONParse.java:296) com.glide.script.JSONParse.tokenize(JSONParse.java:73) com.glide.script.JSONParse.jsFunction_decode(JSONParse.java:53) sun.reflect.GeneratedMethodAccessor489.invoke(Unknown Source) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) java.lang.reflect.Method.invoke(Method.java:597) org.mozilla.javascript.FunctionObject.doInvoke(FunctionObject.java:597) org.mozilla.javascript.FunctionObject.callVarargs(FunctionObject.java:613) org.mozilla.javascript.FunctionObject.call(FunctionObject.java:457) org.mozilla.javascript.ScriptRuntime.call(ScriptRuntime.java:1227) org.mozilla.javascript.gen.c899.call(sys_script_include.d2426c9ec0a8016501958bf2ac79c775:145) org.mozilla.javascript.ScriptRuntime.call(ScriptRuntime.java:1227) org.mozilla.javascript.gen.c900.call(sys_script_include.d2426c9ec0a8016501958bf2ac79c775:158) org.mozilla.javascript.ScriptRuntime.call(ScriptRuntime.java:1227) org.mozilla.javascript.gen.c2814.call(<refname>:13) org.mozilla.javascript.gen.c2814.exec(<refname>) com.glide.script.ScriptEvaluator.execute(ScriptEvaluator.java:233) com.glide.script.ScriptEvaluator.evaluateString(ScriptEvaluator.java:105) com.glide.script.ScriptEvaluator.evaluateString(ScriptEvaluator.java:72) com.glide.script.ScriptEvaluator.evaluateString(ScriptEvaluator.java:63) com.glide.script.Evaluator.evaluateString(Evaluator.java:91) com.glide.update.UpdateManager2.testFixScript(UpdateManager2.java:600) com.snc.apps.ScriptFixXMLHttpProcessor$ScriptFixWorker.evaluateScript(ScriptFixXMLHttpProcessor.java:122) com.snc.apps.ScriptFixXMLHttpProcessor$ScriptFixWorker.startWork(ScriptFixXMLHttpProcessor.java:100) com.glide.worker.AbstractProgressWorker.startAndWait(AbstractProgressWorker.java:86) com.glide.worker.ProgressWorker.startAndWait(ProgressWorker.java:52) com.glide.worker.AbstractProgressWorker.start(AbstractProgressWorker.java:67) com.snc.apps.ScriptFixXMLHttpProcessor.process(ScriptFixXMLHttpProcessor.java:77) com.glide.processors.XMLHttpProcessor.processJavaAJAX(XMLHttpProcessor.java:143) com.glide.processors.XMLHttpProcessor.process(XMLHttpProcessor.java:100) com.glide.processors.AProcessor.runProcessor(AProcessor.java:409) com.glide.processors.AProcessor.processTransaction(AProcessor.java:183) com.glide.processors.ProcessorRegistry.process(ProcessorRegistry.java:165) com.glide.ui.GlideServletTransaction.process(GlideServletTransaction.java:32) com.glide.sys.ServletTransaction.run(ServletTransaction.java:34) java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918) java.lang.Thread.run(Thread.java:682)
Evaluator: java.util.NoSuchElementException       Caused by error in Script Include: 'JSON' at line 158           155:          3. Invalid JSON is accepted (member names not enclosed in quotes)         156:          4. Bare encoded strings are decoded twice.         157: */ ==> 158: JSON.parse = function(s) { return new JSON().decode(s); };         159:           160:          /*         161:          Convert a JS object to a JSON string.   Note that this is not completely ES5 compatible:   java.util.LinkedList.remove(LinkedList.java:788) java.util.LinkedList.removeFirst(LinkedList.java:134) java.util.LinkedList.pop(LinkedList.java:601) com.glide.script.JSONParse.handleObjectEnd(JSONParse.java:296) com.glide.script.JSONParse.tokenize(JSONParse.java:73) com.glide.script.JSONParse.jsFunction_decode(JSONParse.java:53) sun.reflect.GeneratedMethodAccessor489.invoke(Unknown Source) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) java.lang.reflect.Method.invoke(Method.java:597) org.mozilla.javascript.FunctionObject.doInvoke(FunctionObject.java:597) org.mozilla.javascript.FunctionObject.callVarargs(FunctionObject.java:613) org.mozilla.javascript.FunctionObject.call(FunctionObject.java:457) org.mozilla.javascript.ScriptRuntime.call(ScriptRuntime.java:1227) org.mozilla.javascript.gen.c899.call(sys_script_include.d2426c9ec0a8016501958bf2ac79c775:145) org.mozilla.javascript.ScriptRuntime.call(ScriptRuntime.java:1227) org.mozilla.javascript.gen.c900.call(sys_script_include.d2426c9ec0a8016501958bf2ac79c775:158) org.mozilla.javascript.ScriptRuntime.call(ScriptRuntime.java:1227) org.mozilla.javascript.gen.c2814.call(<refname>:13) org.mozilla.javascript.gen.c2814.exec(<refname>) com.glide.script.ScriptEvaluator.execute(ScriptEvaluator.java:233) com.glide.script.ScriptEvaluator.evaluateString(ScriptEvaluator.java:105) com.glide.script.ScriptEvaluator.evaluateString(ScriptEvaluator.java:72) com.glide.script.ScriptEvaluator.evaluateString(ScriptEvaluator.java:63) com.glide.script.Evaluator.evaluateString(Evaluator.java:91) com.glide.update.UpdateManager2.testFixScript(UpdateManager2.java:600) com.snc.apps.ScriptFixXMLHttpProcessor$ScriptFixWorker.evaluateScript(ScriptFixXMLHttpProcessor.java:122) com.snc.apps.ScriptFixXMLHttpProcessor$ScriptFixWorker.startWork(ScriptFixXMLHttpProcessor.java:100) com.glide.worker.AbstractProgressWorker.startAndWait(AbstractProgressWorker.java:86) com.glide.worker.ProgressWorker.startAndWait(ProgressWorker.java:52) com.glide.worker.AbstractProgressWorker.start(AbstractProgressWorker.java:67) com.snc.apps.ScriptFixXMLHttpProcessor.process(ScriptFixXMLHttpProcessor.java:77) com.glide.processors.XMLHttpProcessor.processJavaAJAX(XMLHttpProcessor.java:143) com.glide.processors.XMLHttpProcessor.process(XMLHttpProcessor.java:100) com.glide.processors.AProcessor.runProcessor(AProcessor.java:409) com.glide.processors.AProcessor.processTransaction(AProcessor.java:183) com.glide.processors.ProcessorRegistry.process(ProcessorRegistry.java:165) com.glide.ui.GlideServletTransaction.process(GlideServletTransaction.java:32) com.glide.sys.ServletTransaction.run(ServletTransaction.java:34) java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918) java.lang.Thread.run(Thread.java:682)
Evaluator: java.util.NoSuchElementException       Caused by error in script at line 13             10:                 11: var responseBody = response.getBody(); // stringified JSON returned info               12:       ==>   13: var parsed = JSON.parse(responseBody); // turn it into a true JSON object               14:                 15: // Now we can begin using the response               16: gs.print(responseBody);       java.util.LinkedList.remove(LinkedList.java:788) java.util.LinkedList.removeFirst(LinkedList.java:134) java.util.LinkedList.pop(LinkedList.java:601) com.glide.script.JSONParse.handleObjectEnd(JSONParse.java:296) com.glide.script.JSONParse.tokenize(JSONParse.java:73) com.glide.script.JSONParse.jsFunction_decode(JSONParse.java:53) sun.reflect.GeneratedMethodAccessor489.invoke(Unknown Source) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) java.lang.reflect.Method.invoke(Method.java:597) org.mozilla.javascript.FunctionObject.doInvoke(FunctionObject.java:597) org.mozilla.javascript.FunctionObject.callVarargs(FunctionObject.java:613) org.mozilla.javascript.FunctionObject.call(FunctionObject.java:457) org.mozilla.javascript.ScriptRuntime.call(ScriptRuntime.java:1227) org.mozilla.javascript.gen.c899.call(sys_script_include.d2426c9ec0a8016501958bf2ac79c775:145) org.mozilla.javascript.ScriptRuntime.call(ScriptRuntime.java:1227) org.mozilla.javascript.gen.c900.call(sys_script_include.d2426c9ec0a8016501958bf2ac79c775:158) org.mozilla.javascript.ScriptRuntime.call(ScriptRuntime.java:1227) org.mozilla.javascript.gen.c2814.call(<refname>:13) org.mozilla.javascript.gen.c2814.exec(<refname>) com.glide.script.ScriptEvaluator.execute(ScriptEvaluator.java:233) com.glide.script.ScriptEvaluator.evaluateString(ScriptEvaluator.java:105) com.glide.script.ScriptEvaluator.evaluateString(ScriptEvaluator.java:72) com.glide.script.ScriptEvaluator.evaluateString(ScriptEvaluator.java:63) com.glide.script.Evaluator.evaluateString(Evaluator.java:91) com.glide.update.UpdateManager2.testFixScript(UpdateManager2.java:600) com.snc.apps.ScriptFixXMLHttpProcessor$ScriptFixWorker.evaluateScript(ScriptFixXMLHttpProcessor.java:122) com.snc.apps.ScriptFixXMLHttpProcessor$ScriptFixWorker.startWork(ScriptFixXMLHttpProcessor.java:100) com.glide.worker.AbstractProgressWorker.startAndWait(AbstractProgressWorker.java:86) com.glide.worker.ProgressWorker.startAndWait(ProgressWorker.java:52) com.glide.worker.AbstractProgressWorker.start(AbstractProgressWorker.java:67) com.snc.apps.ScriptFixXMLHttpProcessor.process(ScriptFixXMLHttpProcessor.java:77) com.glide.processors.XMLHttpProcessor.processJavaAJAX(XMLHttpProcessor.java:143) com.glide.processors.XMLHttpProcessor.process(XMLHttpProcessor.java:100) com.glide.processors.AProcessor.runProcessor(AProcessor.java:409) com.glide.processors.AProcessor.processTransaction(AProcessor.java:183) com.glide.processors.ProcessorRegistry.process(ProcessorRegistry.java:165) com.glide.ui.GlideServletTransaction.process(GlideServletTransaction.java:32) com.glide.sys.ServletTransaction.run(ServletTransaction.java:34) java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918) java.lang.Thread.run(Thread.java:682)
Evaluator: java.util.NoSuchElementException       Caused by error in script at line -1 java.util.LinkedList.remove(LinkedList.java:788) java.util.LinkedList.removeFirst(LinkedList.java:134) java.util.LinkedList.pop(LinkedList.java:601) com.glide.script.JSONParse.handleObjectEnd(JSONParse.java:296) com.glide.script.JSONParse.tokenize(JSONParse.java:73) com.glide.script.JSONParse.jsFunction_decode(JSONParse.java:53) sun.reflect.GeneratedMethodAccessor489.invoke(Unknown Source) sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) java.lang.reflect.Method.invoke(Method.java:597) org.mozilla.javascript.FunctionObject.doInvoke(FunctionObject.java:597) org.mozilla.javascript.FunctionObject.callVarargs(FunctionObject.java:613) org.mozilla.javascript.FunctionObject.call(FunctionObject.java:457) org.mozilla.javascript.ScriptRuntime.call(ScriptRuntime.java:1227) org.mozilla.javascript.gen.c899.call(sys_script_include.d2426c9ec0a8016501958bf2ac79c775:145) org.mozilla.javascript.ScriptRuntime.call(ScriptRuntime.java:1227) org.mozilla.javascript.gen.c900.call(sys_script_include.d2426c9ec0a8016501958bf2ac79c775:158) org.mozilla.javascript.ScriptRuntime.call(ScriptRuntime.java:1227) org.mozilla.javascript.gen.c2814.call(<refname>:13) org.mozilla.javascript.gen.c2814.exec(<refname>) com.glide.script.ScriptEvaluator.execute(ScriptEvaluator.java:233) com.glide.script.ScriptEvaluator.evaluateString(ScriptEvaluator.java:105) com.glide.script.ScriptEvaluator.evaluateString(ScriptEvaluator.java:72) com.glide.script.ScriptEvaluator.evaluateString(ScriptEvaluator.java:63) com.glide.script.Evaluator.evaluateString(Evaluator.java:91) com.glide.update.UpdateManager2.testFixScript(UpdateManager2.java:600) com.snc.apps.ScriptFixXMLHttpProcessor$ScriptFixWorker.evaluateScript(ScriptFixXMLHttpProcessor.java:122) com.snc.apps.ScriptFixXMLHttpProcessor$ScriptFixWorker.startWork(ScriptFixXMLHttpProcessor.java:100) com.glide.worker.AbstractProgressWorker.startAndWait(AbstractProgressWorker.java:86) com.glide.worker.ProgressWorker.startAndWait(ProgressWorker.java:52) com.glide.worker.AbstractProgressWorker.start(AbstractProgressWorker.java:67) com.snc.apps.ScriptFixXMLHttpProcessor.process(ScriptFixXMLHttpProcessor.java:77) com.glide.processors.XMLHttpProcessor.processJavaAJAX(XMLHttpProcessor.java:143) com.glide.processors.XMLHttpProcessor.process(XMLHttpProcessor.java:100) com.glide.processors.AProcessor.runProcessor(AProcessor.java:409) com.glide.processors.AProcessor.processTransaction(AProcessor.java:183) com.glide.processors.ProcessorRegistry.process(ProcessorRegistry.java:165) com.glide.ui.GlideServletTransaction.process(GlideServletTransaction.java:32) com.glide.sys.ServletTransaction.run(ServletTransaction.java:34) java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895) java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918) java.lang.Thread.run(Thread.java:682)
[0:00:01.495] Total Time
Mega Sage
Mega Sage

Sagar:



I'm not sure; I have not see that error before when working with this.   Is it consistent, does it happen every time?   I have attached my script to the article for download.   Give that a try and see if it works.



Steven


ServiceNow Employee
ServiceNow Employee

What version are you on? I think JSON.parse demands helsinki, but might be wrong.



//Göran


Mega Sage
Mega Sage

Goran:



Not sure, but I don't think that is the issue.   I have been using JSON for a couple of years+ in ServiceNow.   Fuji definitely had the libraries.



Steven.


ServiceNow Employee
ServiceNow Employee

Ahh mixed it all together from this blog post: ECMAScript 5 in ServiceNow Helsinki!


just remember "helsinki" from the title and something about JSON.parse was added as a class function, but just that part was with "recent release".


Mega Sage
Mega Sage

Yeah, had forgotten that article.   Hmmm, maybe you are right.   I will have to go and see if I can find a Geneva or earlier instance, and play a bit.   Let you know.



I did these articles on Geneva:


Mini-Lab: Using Ajax and JSON to Send Objects to the Server - 1/26/2016


Mini-Lab: Writing Entries Into the System Log Using Ajax and JSON - 1/28/2016



I didn't publish anything JSON before that, but I swear I used it waaay before that, and it wasn't a library port either.   😕



Kilo Contributor

Hi,



I was using Geneva instance.


One more weird thing happened, when I tried to retrieve the update set you have attached in this post in my dev instance it was not getting added. Once I click on upload button its redirecting me to retrieved update sets list. I tried it to retrieve it in a fresh dev instance too but same issue, update set is not added in the list.



Thanks & regards


Mega Sage
Mega Sage

Sagar:



That XML was a direct to table file, not an update set.     In other words when you upload it using Import XML it will end up in the Fix Scripts table.   Check there.   🙂



Okay, did a little research.   Looks like some things were actually in Geneva, not sure what patch.   Now, the interesting part.   JSON.stringify, and JSON.parse are both ECMA 5.1 and later!   Sooo, looks like you called it Goran!



JSON.parse() - JavaScript | MDN


JSON.stringify() - JavaScript | MDN



Where does this leave you?   Well, there is a Polyfill for this.   You could implement that as a Script Include on your instance and see if that allows the example to work.



JSON 3 <-- JSON Polyfill definition with .parse and .stringify



Awhile back I wrote an article on how to implement Polyfills in ServiceNow.   You might give it a try and see if it fixes the issue.



Mini-Lab: Extending ServiceNow JavaScript Using ECMAScript 6 Polyfills



Clarification:   You will need to implement the JSON 3 polyfill to possibly get this to work.   My article does not describe the JSON implementation, just a how to do polyfills in ServiceNow.



Steven.


ServiceNow Employee
ServiceNow Employee

can't Sagar use the JSON.encode() and JSON.decode? those works in Geneva right?


Mega Sage
Mega Sage

Goran:



Yeah, but not so easy to use in this case.   You would still need to parse the stringified JSON somehow.   Decode won't work on it I believe.



Steven.


Mega Guru

Thanks Steve Bell for this step-by-step example, it's really helpful.



Remark: I think that in the point 6, you wanted to say "http://catfacts-api.appspot.com/api/facts?number=5" and not "http://www.programmableweb.com/api/cat-facts?number=${number}", don't you ? The latter returns HTML content and not JSON


html-content.png



while the other return JSON content as expected


JSON-content.png


Mega Sage
Mega Sage

Ximizu:



Thank you, and yes!   The screen shot wasn't completely accurate either.   Great catch, thank you!   The article has been corrected.



Steven.


Mega Guru

Hello Steve,


This post was really awesome as very new to this.



I have followed your step and but got an issue.



I am not able to get this in json format but http status is 200.What might be the issue here.Please help..



find_real_file.png