Performing web service interaction in ServiceNow with JSON is becoming a more popular discussion point among customers and partners alike. I decided to draw up a PHP implementation of performing Inserts, Updates, Queries, and Deletions of ServiceNow records via the JSON web service interface.
Please note, in order for you to utilize JSON web services with ServiceNow, you will need to enable the appropriate plugin. Please refer to the official documentation for JSON Web Services on the ServiceNow wiki.
Essentially the JSON interface utilizes a combination of URLs and POST data to perform the interaction with ServiceNow. All authentication is done via Basic Authentication.
cURL has an easy set of libraries and tools that allow us to perform these operations.
First we use cURL to prepare an HTTP POST to our URL using the following syntax:
1 2 | $query = "https://myinstance.service-now.com/incident.do?JSON&sysparm_action=insert"; $curl = curl_init($query); |
The above snippet initialized cURL to be prepared to visit the incident table using a JSON processor. The sysparm_action parameter tells the web service what type of operation we want to perform. In this case it is “insert”. See the documentation for all available actions.
In order to authenticate into the instance in your HTTP Request you will use the following syntax (assume your username is “John” and your password is “SecurePass”:
1 2 | curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($curl, CURLOPT_USERPWD, "John:SecurePass"); |
Some requests require a JSON formatted query string to be send with your posted request. The “insert” operation does require JSON string that provides the fields and corresponding values that you will be setting in your new record. You set this up similar to the following snippet:
1 2 3 4 | $jsonInput = '{"short_description":"My First JSON incident","priority":"1"}'; curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-Type: application/json")); curl_setopt($curl, CURLOPT_POSTFIELDS, $jsonInput); |
That code tells cURL to send a POST request sending the specific JSON body. In this example, the JSON string indicates that we will create an incident with a short_description and priority.
You then send the request by using something like the following:
1 2 |
That sends the request, stores the response into a variable, and closes the connection. You can then convert the resulting JSON string in the response variable to a PHP object doing the following:
1 |
Since there are several different actions available, and each action is a bit different, I created a script that provides you a sample of using all of the available JSON Web Service actions.
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 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | <?php //Setup $instance = "demo"; $username = "admin"; $password = "admin"; $table = "cmdb_ci_database"; $printFields = array("sys_id", "name", "type", "version"); //Create a MySQL Database Server echo "<br><br>Create a MySQL Database Server<br>"; $filter = ""; $json = '{"name":"MySQL DB #3","type":"MySQL","version":"1.0.0"}'; $res = jsonQuery($instance, $username, $password, $table, "insert", $filter, $json); $newDbServer = $res->records[0]->sys_id; printRecord($res, $printFields); //Get the newly created MySQL Server echo "<br><br>Get the newly created MySQL Server<br>"; $filter = ""; $json = '{"sysparm_sys_id":"'.$newDbServer.'"}'; $res = jsonQuery($instance, $username, $password, $table, "get", $filter, $json); printRecord($res, $printFields); // Update newly created MySQL Server echo "<br><br>Update newly created MySQL Server<br>"; $filter = "sys_id%3D$newDbServer"; $json = '{"version":"2.0.0"}'; $res = jsonQuery($instance, $username, $password, $table, "update", $filter, $json); printRecord($res, $printFields); // Delete newly created MySQL Server echo "<br><br>Delete newly created MySQL Server<br>"; $filter = ""; $json = "{"sysparm_sys_id":"$newDbServer"}"; $res = jsonQuery($instance, $username, $password, $table, "deleteRecord", $filter, $json); printRecord($res, $printFields); //Insert Multiple MySQL Server Records echo "<br><br>Insert Multiple MySQL Server Records<br>"; $filter = ""; $json = '{"records":[{"name":"MySQL DB #3","type":"MySQL","version":"1.0.0"},'. '{"name":"MySQL DB #3","type":"MySQL","version":"1.2.0"}]}'; $res = jsonQuery($instance, $username, $password, $table, "insert", $filter, $json); $newDbServer = $res->records[0]->sys_id; printRecord($res, $printFields); //getKeys of all MySQL Records that have the name: MySQL DB #3 echo "<br><br>getKeys of all MySQL Records that have the name: MySQL DB #3<br>"; $filter = "name%3DMySQL%20DB%20%233"; $json = ""; $res = jsonQuery($instance, $username, $password, $table, "getKeys", $filter, $json); //printRecord($res, $printFields); foreach($res->records as $key) echo "[sys_id]: $key<BR>"; // Delete all MySQL Servers with this name: MySQL DB #3 echo "<br><br>Delete all MySQL Servers with this name: MySQL DB #3<br>"; $filter = "name%3DMySQL%20DB%20%233"; $json = ""; $res = jsonQuery($instance, $username, $password, $table, "deleteMultiple", $filter, $json); printRecord($res, $printFields); // List MySQL Databases echo "<br><br>List current MySQL Databases<br>"; $filter = "type%3DMySQL"; $json = ""; $res = jsonQuery($instance, $username, $password, $table, "getRecords", $filter, $json); printRecord($res, $printFields); function jsonQuery($instance, $username, $password, $table, $action, $encodedQuery, $jsonInput){ $query = "https://$instance.service-now.com/$table.do?JSON&" . "sysparm_action=$action"; if($encodedQuery) $query .= "&sysparm_query=$encodedQuery"; $curl = curl_init($query); curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($curl, CURLOPT_USERPWD, "$username:$password"); curl_setopt($curl, CURLOPT_VERBOSE, 1); curl_setopt($curl, CURLOPT_HEADER, false); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); if( $jsonInput ){ curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_HTTPHEADER, array("Content-Type: application/json")); curl_setopt($curl, CURLOPT_POSTFIELDS, $jsonInput); } $response = curl_exec($curl); curl_close($curl); $json = json_decode($response); if ($json != "" && property_exists($json, 'error')){ throw new ErrorException("SN JSON Error: {$json->error}"); } return $json; } function printRecord($obj, $fields){ if(!obj || !$obj->records) return; foreach($obj->records as $rec){ foreach($rec as $key => $value){ if( in_array($key, $fields ) ) echo "[$key]: $value; "; } echo "<BR>"; } } ?> |
Running this script provides an output similar to the following screen shot:
John,
Is this how you can access your service-now instance externally using PHP? I’m going to try what you have here on the demo. Thanks for the post! Very compelling!
Yes, Shane, this is one way you can do it. You can also use SOAP web services with PHP to interact with your ServiceNow instance as well.
John – FYI… getting some errors when trying to run your php. Copied and pasted your script above and saved as sn_demo_php.php – ran from my server…
Insert Multiple MySQL Server Records
Warning: Invalid argument supplied for foreach() in /homepages/sn_demo_php.php on line 103
getKeys of all MySQL Records that have the name: MySQL DB #3
Warning: Invalid argument supplied for foreach() in /homepages/sn_demo_php.php on line 54
Shane,
You need to make sure that the instance you are running this script against has the JSON plugin activated.
If you are running against demo.service-now.com, then it will fail because the plugin is not turned onto that instance by default.
Totally helps explain it 🙂 thanks John!
John,
$action
What is the value of $action?
Thanks
The sysparm_action parameter tells the web service what action we are hoping to perform with the request (insert, update, delete, etc). The $action variable is what I sent into the function to be placed as the value for the “sysparm_action” parameter.
Hi John,
Been trying to get this to work with our instance… JSON is turned on.
Invalid argument supplied for foreach()
function printRecord($obj, $fields){
foreach($obj->records as $rec){
foreach($rec as $key => $value){
if( in_array($key, $fields ) ) echo “[$key]: $value; “;
}
echo “”;
}
}
Sorry, I just can’t figure this one out on my own so I’m turning to you. Json working on our instance
https://myinstance.service-now.com/sys_report_template.do?JSON&jvar_report_id=b9b06c220a0a3c8b011ca31372fc914b
Everything online has something to do with an array issue. Thanks – Shane
What is $filter = “type%3DMySQL”;
Could that be my issue?
Hi John,
Can we use XML instead of JSON in the url? Ex-
https://demo.service-now.com/incident.do?XML&sysparm_action=getRecords&sys_id%3D14ab928dc6112275008c6e047597484d
I have tested it to be working. But still I am not sure. Please confirm me.
Yes you can as there is an XML web service with ServiceNow. Check out the documentation at:
http://wiki.service-now.com/index.php?title=XML_Web_Service
Hi John,
Thank you very much for the reply. I checked the link you sent.
But can we do insert and update with that XML web service?
And can you send me the format of query or filter string ? Is it like an SQL statement after where clause like Salesforce CRM?
Sukarna,
No, the XML web service is just for querying. However, if you are unable to send XML via SOAP, then you could possibly try the technique used in this blog post:
https://john-james-andersen.com/blog/service-now/submit-xml-to-servicenow-via-http-post.html
Not sure if that is what you are looking for, but it is another alternative.
For encoded queries…see the following wiki page:
http://wiki.service-now.com/index.php?title=Embedded:Encoded_Query_Strings
Especially check out the last section of using filters to set up your query.
-John
Hello John,
Thank you very very much for your time.
My requirements for query is almost achieved. By referring to
http://wiki.service-now.com/index.php?title=Direct_Web_Services
and doing some trial and error, it is found that =, !=, LIKE, NOT LIKE operators are supported.
For your information, I decided to use soapclient class of PHP as suggested at(http://community.service-now.com/forum/4048).
For one thing, I would like your suggestion on retrieving all available tables(http://wiki.service-now.com/index.php?title=Tables_and_Classes) which is around 248.
Is there any request, that can be made to serivce-now to get the names of these tables?
@sukarna – as for my suggestion on retrieving all available tables….this seems to work the best for me:
https://demo.service-now.com/sys_dictionary_list.do?sysparm_query=internal_type%3Dcollection
You could use that encoded query to get results through any ServiceNow web service (if you have proper access rights).
Hello John,
Again many thanks for your suggestion. I tried it and got 1425 names of tables.
But my question is ‘Are these all can be queried, updated and inserted into, by a normal and admin user ?’
‘Is there any rule to filter them into categories like(queryable, updatable) by admin/normal user ?’
Hi John,
This is really helpful. It would be really great if could you also give us some little sneak into internal code for this tool. I am trying to achieve something similar but using Java’s Jersey client. Below is a sample code which I am trying to execute for one of our Service-now instance, but I always end up getting 401 error. Any idea?
Client client = Client.create();
String auth = new String(Base64.encode(“xyz:password”));
WebResource webResource = client
.resource(“https://xyz/sys_user.do?JSON&user_name=melinda.carleton”);
webResource.header(“Authorization”, “Basic” + auth);
ClientResponse response = webResource.accept(“application/json”).get(
ClientResponse.class);
if (response.getStatus() != 200) {
throw new RuntimeException(“Failed : HTTP error code : ”
+ response.getStatus());
}
String output = response.getEntity(String.class);
System.out.println(“Output from Server …. \n”);
System.out.println(output);
Thanks,
Dhananjay
@Dhananjay, I am not using Java on this tool, but rather PHP.
I would recommend you check out a blog post I entered with ServiceNow javascript calling into standard Java code to do HTTP REST-like calls long before we had a REST library set in ServiceNow. It may provide some guidance.
Here is a link to that post: https://john-james-andersen.com/blog/service-now/service-now-is-not-afraid-to-get-rest.html
Hi John,
In this example, ServiceNow will receive the JSON document you given as ‘{“short_description”:”My First JSON incident”,”priority”:”1″}’. And ServiceNow will automatically insert the short_description and priority into incident table.
What happened when the field strings in the received JSON document are different from the incident. For example, what can I do when the received JSON document is like this ‘{“short_desc”:”My First JSON incident”,”priority”:”1″}’. How do tell ServiceNow that I want to map the short_desc in JSON document to the Short_description in Incident table? Can you share some example code to map/convert the field string in this case?
Thank you,
Jason