I have had a few people over the past week ask me for some basic guidance on how to handle SOAP responses within ServiceNow scripts. I thought I would create this simple tutorial that will help you build out a SOAP request and use the information that comes back from the third party web service.
For this example, we are going to create the following feature. Let’s pretend that your CEO loves Anagrams. In fact, he loves them so much that he has the janitorial staff put a list of anagrams on everyone’s desk in the morning. The first thing you MUST do before you start the day is to solve your list of anagrams. The IT folks caught on fast, and started to use ServiceNow Live Feed to ask their coworkers for help on certain anagrams. Well you, the new ServiceNow IT specialist, saw this happening and decided to make everyone’s life easier. You decide to create a feature on the Live Feed so that when someone types “Anagram: ” and then a word that your script will reply to that live message instantly with a possible answer. (See the picture at the top of this post as an example).
In order to do this, you decide to consume a public web service at AonAware.com They offer a SOAP endpoint that accepts anagrams and provides a list of possible answers. Once it finds a good answer, it also provides suggestions for other words that can be made out of a subset of those characters.
The first step is to create a SOAP Message record that will set up ServiceNow to consume that SOAP endpoint.
The SOAP WSDL for the Anagram Web Service is:
http://services.aonaware.com/CountCheatService/CountCheatService.asmx?WSDL
Upon creating the new “SOAP Message” record, you will give it a name. For this example you will name it “Anagrams”. You will also need to provide it a WSDL. To do this you will unlock the WSDL field and paste the WSDL inside the edit field that appears. Once you have done this, you will click on the “Generate sample SOAP message” link at the bottom of the page. This will save your SOAP Message record and then it will query the WSDL and generate all of the supported Web Service functions listed in the WSDL.
After the SOAP Message record is generated, you will have a list of SOAP message functions that are generated as well. The message function that we will use is: “CountCheatServiceSoap.LetterSolutions“.
Click on the CountCheatServiceSoap.LetterSolutions record to set it up for our scripts.
You are now going to modify the SOAP Envelope so that we can pass variable values into the SOAP Request rather than just static text. In the SOAP Message feature set, we indicate variables using the following syntax: ${varName}.
In this SOAP message function, there is only one parameter that we pass into the web service. It is the anagram tag. The SOAP Message record will default to the type value. You will replace it with the variable: ${anagram}. Once you have done that, click the “Update” button to save the record.
We do have the option to have ServiceNow generate a few lines of code to help us start using the SOAP Message consumer that we just created. In order to generate that code, you go into your SOAP Message Function that you just modified, and click the link: “Preview script usage”.
Once you do this a dialog will appear with some sample code. Copy that code to your clipboard so that we can start coding our new feature.
Now that we have our SOAP Web Service Consumer set up, we want to now create the script that is going to query the web service and handle the response. Since we want to watch the “Live Feed” messages for any matching “Anagram: ” conventions, we will need to create a business rule on the live_message table for new messages. When a new message fits our anagram query format, then we will query the web service.
So, create a business rule for the “live_message” table. Let’s name the business rule: “Anagram Solver”. Set it to occur “After” and only on an “Insert“. Also, we only want the business rule to execute if the live message is in the “Anagram: ” format. So, we will set the condition on our business rule to be:
1 | current.message.match(/^anagram\:.*/i)!=undefined |
Now we are going to build out the actual script for the business rule. First of all, I like to encapsulate my business rule code into its own function. So, starting out, my script is going to look like this:
1 2 3 4 5 | getPossibleAnagramSolution(); function getPossibleAnagramSolution(){ } |
Now, we will put all of our logic and work inside of the getPossibleAnagramSolution() function.
We start off by pasting the template code that was generated by our SOAP Message function in one of our previous steps. When we do this, our code will now look like the following:
1 2 3 4 5 6 | getPossibleAnagramSolution(); function getPossibleAnagramSolution(){ var s = new SOAPMessage('Anagrams', 'CountCheatServiceSoap.LetterSolutions'); var response = s.post(); } |
In this code we have set “s” to be an instance of the SOAP Message class. The two parameters that we pass into that constructor were the SOAP Message name as well as the SOAP Message Function in the second parameter.
The second line is the line that actually sends the SOAP request to the web service. We can’t really run this yet because we need to first set the “${anagram}” variable that we created inside of our SOAP Message Function.
Our next step is to get the anagram from the live message so that we can set it in our SOAP Message function. To do this, we will use some Regular Expressions on the “current.message” live_message field to pull out the anagram from the message. Once we pull it out, we will use the “setParameter” method for SOAP message to set the anagram variable to the anagram string from the live feed post. Then, we will send the SOAP request out to the web service provider.
The subset of code to do this will look like this:
1 2 3 4 5 6 7 8 9 10 11 | //identify the anagram from the message string var tokens = /^anagram\:\s*([a-zA-Z]*)$/i(current.message); //If there was an anagram string, we will set it as the "anagram" variable in //our SOAP Message Function if(tokens && tokens.length > 1){ //Setting the anagram variable in our SOAP message s.setParameter('anagram', tokens[1] ); //Send the request var response = s.post(); } |
Please note, this will send the SOAP request out synchronously, which means we will be held up until we get a response from the web service.
If you want to have a record of these SOAP requests and responses, as well as take advantage of retry policies, etc, you can have these SOAP communications go through the ECC Queue by changing your “post()” to pass in a “true” as an optional parameter:
1 | var response = s.post(true); |
For this example, however, we are going to not use the ECC Queue. That is a topic for another day. So far, our business rule code looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | getPossibleAnagramSolution(); function getPossibleAnagramSolution(){ var s = new SOAPMessage('Anagrams', 'CountCheatServiceSoap.LetterSolutions'); var tokens = /^anagram\:\s*([a-zA-Z]*)$/i(current.message); //If there was an anagram string, we will set it as the "anagram" variable in //our SOAP Message Function if(tokens && tokens.length > 1){ //Setting the anagram variable in our SOAP message s.setParameter('anagram', tokens[1] ); //Send the request var response = s.post(); } } |
We have saved the Web Service response in a variable called “response”. We can now do things with this response.
First of all, it is important to note that the response is a string. You could print out the response to the system log if you wanted, you could also do searches on the string as well. However, in order to get data from the XML it is usually cleaner and more reliable to convert that string to an actual XML Document. In order to do this, we will use the following code:
1 | var xmlDoc = new XMLDocument(response); |
Now that we have converted the XML string into an XML Document object, we have several methods that we can use to traverse the XML document. You can get a good feel for those methods off of the ServiceNow wiki page for the XMLDocument object.
The method that we will use is the getNodeText() method. With this method we will use an XPATH statement to tell getNodeText() to grab the text within that exact node.
A typical response of this web service for an anagram string of “itmes” could look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <soap:Envelope > <soap:Body> <LetterSolutionsResponse > <LetterSolutionsResult> <string>emits</string> <string>items</string> <string>mites</string> <string>smite</string> <string>times</string> <string>emit</string> <string>item</string> <string>mist</string> <string>mite</string> <string>semi</string> <string>site</string> <string>stem</string> <string>ties</string> <string>time</string> </LetterSolutionsResult> </LetterSolutionsResponse> </soap:Body> </soap:Envelope> |
In our example, we want to only choose the first choice provided by the web service. We don’t care about providing all alternatives that the web service is responding with. In order to do this, we will use an XPATH string of:
//LetterSolutionsResult/string[1]
It is recommended that you get familiar with XPATH when traversing through XML documents. It is beyond this post, so we will not pursue it further.
The javascript code used to get the first result from the SOAP response would be:
1 2 | //Grab the first solution offered by the web service var result = xmlDoc.getNodeText("//LetterSolutionsResult/string[1]"); |
Now that we have the first solution, we will create a new “live message” record that will be a response to the initial anagram query. The javascript for this would look like:
1 2 3 4 5 6 7 8 9 10 11 12 | //Generate a new live_message record object var reply = new GlideRecord("live_message"); //This new message will be a reply to the message we are currently processing reply.reply_to = current.sys_id; //We'll set our post with the current time reply.last_activity = gs.nowDateTime(); //We'll just set our reply person as the person who made the original request reply.profile = current.profile; //Our reply message will just contain the first solution from the web service reply.message = result; //Insert this message into the Live Feed reply.insert(); |
There you have it. The full business rule script will look like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | getPossibleAnagramSolution(); function getPossibleAnagramSolution(){ var s = new SOAPMessage('Anagrams', 'CountCheatServiceSoap.LetterSolutions'); var tokens = /^anagram\:\s*([a-zA-Z]*)$/i(current.message); //If there was an anagram string, we will set it as the "anagram" variable in //our SOAP Message Function if(tokens && tokens.length > 1){ //Setting the anagram variable in our SOAP message s.setParameter('anagram', tokens[1] ); //Send the request var response = s.post(); } //Convert the string into an XML Document var xmlDoc = new XMLDocument(response); //Grab the first solution offered by the web service var result = xmlDoc.getNodeText("//LetterSolutionsResult/string[1]"); //Generate a new live_message record object var reply = new GlideRecord("live_message"); //This new message will be a reply to the message we are currently processing reply.reply_to = current.sys_id; //We'll set our post with the current time reply.last_activity = gs.nowDateTime(); //We'll just set our reply person as the person who made the original request reply.profile = current.profile; //Our reply message will just contain the first solution from the web service reply.message = result; //Insert this message into the Live Feed reply.insert(); } |
Hey John,
Enjoyed reading it !
Thanks !
Yes,Realy Good 🙂
Thank you!!
Hi John! Great stuff, thank you. I do have a question, though. How would you capture all the values? I have a situation where I’m trying to use XPATH to do exactly this, but the variable I’m creating is coming back as undefined. Any suggestions?
Thank you!
@Tim…XPATH can be powerful, but tricky…especially when dealing with Namespaces. I would recommend checking out a couple of wiki pages:
1) https://wiki.servicenow.com/index.php?title=XMLDocument_Script_Object
2) http://wiki.servicenow.com/index.php?title=XMLHelper
These are two different approaches to handling XML strings such as those found in SOAP Responses.
This was very very clear. I have save the URL and will go through more blogs of yours. I really appreciate that because not al share their knowledge. 🙂