NAME

ServiceNow::SOAP - A better perl API for ServiceNow

SYNOPSIS

# return a reference to a session object
$sn = ServiceNow($instancename, $username, $password);

# return a reference to a table object
$table = $sn->table($tablename);

# count records
$count = $table->count(%parameters);

# return a list of sys_ids
@keys = $table->getKeys(%parameters);

# return a single record as a hash
$rec = $table->get(sys_id => $sys_id);

# return a set of records as an array of hashes
@recs = $table->getRecords(%parameters);

# call getKeys and return a query object
$qry = $table->query(%parameters);

# fetch the next chunk of records
@recs = $qry->fetch($numrecs);

# retrieve a record based on a unique key other than sys_id
$rec = $table->getRecord($name => $value);

# insert a record
$sys_id = $table->insert(%parameters);

# insert multiple records
@results = $table->insert(@records);

# update a record
$table->update(%parameters);

EXAMPLES

Create session and table objects.

use ServiceNow::SOAP;

my $sn = ServiceNow("mycompany", $username, $password);

my $computer_tbl = $sn->table("cmdb_ci_computer");
my $incident_tbl = $sn->table("incident");

Retrieve a small number of records.

my @recs = $computer_tbl->getRecords(
    "location.name" => "London", 
    "operational_status" => "1",
    __order_by => "name", 
    __limit => 500);
foreach my $rec (@recs) {
    print $rec->{name}, "\n";
}

Count records.

my $count = $computer_tbl->count(
    "location.name" => "London", 
    "operational_status" => "1");

Retrieve records in chunks.

my $qry = $computer_tbl->query(
    "location.name" => "London", 
    "operational_status" => "1",
    __order_by => "name");
while (@recs = $qry->fetch(200)) {
    foreach my $rec (@recs) {
        print $rec->{name}, "\n";
    }
}

Retrieve all the records in a large table.

my @recs = $computer_tbl->query()->fetchAll();

Insert a record.

my $sys_id = $incident_tbl->insert(
    assignment_group => "Network Support",
    short_description => $short_description,
    impact => 2);

Retrieve a single record based on sys_id.

my $rec = $incident_tbl->get(sys_id => $sys_id);
print "number=", $rec->{number}, "\n";

Retrieve a single record based on number.

my $rec = $incident_tbl->getRecord(number => $number);
print "sys_id=", $rec->{sys_id}, "\n";

Update a record.

$incident_tbl->update(
    sys_id => $sys_id,
    assigned_to => "Fred Luddy",
    incident_state => 2);

DESCRIPTION

This module provides an alternate Perl API for ServiceNow.

Features of this module include:

  • Support for both Direct Web Services and Scripted Web Services.

  • Simplified API which closely mirrors ServiceNow's Direct Web Services API documentation.

  • Robust, easy to use methods for reading large amounts of data which adhere to ServiceNow's best practice recommendations.

EXPORTED FUNCTIONS

ServiceNow

This ServiceNow function (which is essentially an alias for ServiceNow::SOAP::Session->new()) is used to obtain a reference to a Session object. The Session object essentially holds the URL and connection credentials for your ServiceNow instance.

The first argument is the URL or instance name. The second argument is the user name. The third argument is the password.

The fourth (optional) argument is an integer trace level which can be helpful for debugging. For details refer to "DIAGNOSTICS" below.

Syntax

my $sn = ServiceNow($instancename, $username, $password);
my $sn = ServiceNow($instanceurl, $username, $password);
my $sn = ServiceNow($instancename, $username, $password, $tracelevel);

Examples

The following two statements are equivalent.

my $sn = ServiceNow("https://mycompanydev.service-now.com", "soap.perl", $password);
my $sn = ServiceNow("mycompanydev", "soap.perl", $password);

Tracing of Web Services calls can be enabled by passing in a fourth parameter. (See "DIAGNOSTICS" below)

my $sn = ServiceNow("mycompanydev", "soap.perl", $password, 1);

ServiceNow::SOAP::Session

call

This method calls a Scripted Web Service. The input parameters can be passed in as list of key/value pairs or as a hash reference. In a list context this method will return a list of key/value pairs. In a scalar context it will return a hash reference.

Use of this method requires the soap_script role and activation of the "Web Services Provider - Scripted" plugin.

Syntax

my %outputs = $sn->call($name, %inputs);
my $outputs = $sn->call($name, $inputs);

Example

my %outputs = $sn->call('OrderBlackBerry',
    phone_number => '555-555-5555',
    requested_for => 'Fred Luddy');
print "created request ", $outputs{request_number}, "\n";

connect

Use of this method is optional, but sometimes you want to know up front whether your connection credentials are valid. This method tests them by attempting to get the user's profile from sys_user using getRecords, and trapping the error. If successful, the session object is returned. If unsuccessful, null is returned and the error message is in $@.

Syntax

my $sn = ServiceNow($instancename, $username, $password)->connect()
    or die "Unable to connect to $instancename: $@";

loadSession

This method loads the session information (i.e. cookies) from a file. This may be required if you are running the same perl script multiple times (each time in a separate process) and you do not want to establish a separate ServiceNow session each time the script is run. Use "saveSession" to save the session identifier to a file and this method to load the session identifier from the file.

Syntax

$sn->loadSession($filename);

saveSession

This method saves the session information (i.e. cookies) to a file. For usage notes refer to "loadSession" above.

Syntax

$sn->saveSession($filename);

table

Used to obtain a reference to a Table object. The Table object is subsequently used for "ServiceNow::SOAP::Table" methods described below.

Syntax

my $table = $sn->table($tablename);

Example

my $computer_tbl = $sn->table("cmdb_ci_computer");

ServiceNow::SOAP::Table

Table objects are used for ServiceNow's Direct Web Services API. A Table object holds the URI for a SOAP endpoint and the corresponding SOAP::Lite object.

To obtain a Table object, use the "table" method describe above.

These Table object methods provide an interface to the Direct Web Services API: "deleteRecord", "get", "getKeys", "getRecords", "insert", "insertMultiple", "update".

asQuery

This method creates a new Query object from a list of keys. It does not make any Web Services calls. It simply makes a copy of the list. Each item in the list must be a sys_id for the respective table.

Syntax

my $query = $table->asQuery(@keys);

Example

In this example, we assume that @incRecs contains an array of incident records from a previous query. We need an array of sys_user_group records for all referenced assignment groups. We use map to extract a list of assignment group keys from the @incRecs; grep to discard the blanks; and uniq to discard the duplicates. @grpKeys contains the list of sys_user_group keys. This array is then used to construct a new Query using "asQuery". "fetchAll" is used to retrieve the records.

use List::MoreUtils qw(uniq);

my @grpKeys = uniq grep { !/^$/ } map { $_->{assignment_group} } @incRecs;
my @grpRecs = $sn->table("sys_user_group")->asQuery(@grpKeys)->fetchAll();
    

attachFile

If you are using Perl to create incident tickets, then you may have a requirement to attach files to those tickets.

This method implements the attachment creator API. The method requires soap_ecc role.

You will need to specify a MIME type. If no type is specified, this function will use a default type of "text/plain". For a list of MIME types, refer to http://en.wikipedia.org/wiki/Internet_media_type.

When you attach a file to a ServiceNow record, you can also specify an attachment name which is different from the actual file name. If no attachment name is specified, this function will assume that the attachment name is the same as the file name.

This function will die if the file cannot be read.

Syntax

$table->attachFile($sys_id, $filename, $mime_type, $attachment_name);

Example

$incident->attachFile($sys_id, "screenshot.png", "image/png");

columns

This method returns a list of the columns in a table. The list is retrieved from the WSDL.

Syntax

@columns = $table->columns();

count

This method counts the number of records in a table, or the number of records that match a set of parameters.

This method requres installation of the Aggregate Web Service plugin.

Syntax

my $count = $table->count();
my $count = $table->count(%parameters);
my $count = $table->count($encodedquery);

Examples

Count the total number of users:

my $count = $sn->table("sys_user")->count();

Count the number of active users:

my $count = $sn->table("sys_user")->count(active => true);

deleteRecord

Deletes a record. For information on available parameters refer to the ServiceNow documentation on the "deleteRecord" Direct SOAP API method.

Syntax

$table->deleteRecord(sys_id => $sys_id);
$table->deleteRecord($sys_id);

except

This method returns a list of all columns in the table except those in the argument list. The argument(s) to this method can be either a string containing a comma separated list of names or a list of names (i.e. qw). This method returns a string containing a comma separated list of names.

The [only useful] purpose of this function is to that you can pass the result back in as an __exclude_columns extended query parameter.

Syntax

my $names = $table->except(@list_of_columns);
my $names = $table->except($comma_separated_list_of_columns);

Example

This example retrieves the columns sys_id, number and description from the incident table. In other words, the result excludes all columns except sys_id, number and description.

   my $incident = $sn->table("incident");
   my @recs = $incident->getRecords(
       __encoded_query => "sys_created_on>=$datetime,
       __exclude_columns => 
           $incident->except("sys_id,number,description"),
       __limit => 250);

get

This method retrieves a single record based on sys_id. The result is returned as a reference to a hash.

If no matching record is found then null is returned.

For additional information refer to the ServiceNow documentation on the "get" Direct SOAP API method.

Syntax

$rec = $table->get(sys_id => $sys_id);
$rec = $table->get($sys_id);

Example

my $rec = $table->get($sys_id);
print $rec->{name};

getKeys

This method returns a list of keys.

Note that this method returns a list of keys, NOT a comma delimited string.

For additional information on available parameters refer to the ServiceNow documentation on the "getKeys" Direct SOAP API method.

Syntax

@keys = $table->getKeys(%parameters);
@keys = $table->getKeys($encodedquery);

Examples

my $cmdb_ci_computer = $sn->table("cmdb_ci_computer");

my @keys = $cmdb_ci_computer->getKeys(operational_status => 1, virtual => "false");
# or
my @keys = $cmdb_ci_computer->getKeys("operational_status=1^virtual=false");

getRecord

This method returns a single qualifying records. The method returns null if there are no qualifying records. The method will die if there are multiple qualifying records.

This method is typically used to retrieve a record based on number or name.

Syntax

$rec = $table->getRecord(%parameters);
$rec = $table->getRecord($encodedquery);

Example

This example retrieves a change_request record based on number.

my $chgRec = $sn->table("change_request")->getRecord(number => $number);
if ($chgRec) {
    print "Short description = ", $chgRec->{short_description}, "\n";
}
else {
    print "$number not found\n";
}

The following two equivalent examples illustrate the relationship between "getRecord" and "getRecords".

my @recs = $table->getRecords(%parameters);
die "Too many records" if scalar(@recs) > 1;
my $rec = $recs[0];

my $rec = $table->getRecord(%parameters);

getRecords

This method returns a list of records. Actually, it returns a list of hash references. You may pass this method either a single encoded query string, or a list of name/value pairs.

For additional information on available parameters refer to the ServiceNow documentation on the "getRecords" Direct SOAP API method.

Important Note: This method will return at most 250 records, unless you specify a __limit parameter as documented in the ServiceNow wiki under Extended Query Parameters. For reading large amounts of data, it is recommended that you use the Query Object described below.

Syntax

@recs = $table->getRecords(%parameters);
@recs = $table->getRecords($encodedquery);

Example

my $sys_user_group = $sn->table("sys_user_group");
my @grps = $sys_user_group->getRecords(
    active => true, __limit => 500, __order_by => "name");
foreach my $grp (@grps) {
    print $grp->{name}, "\n";
}

insert

This method inserts a record. In a scalar context, this method returns a sys_id only. In a list context, this method returns a list of name/value pairs.

For information on available parameters refer to the ServiceNow documentation on the "insert" Direct SOAP API method.

Syntax

my $sys_id = $table->insert(%values);
my %result = $table->insert(%values);

Examples

my $incident = $sn->table("incident");

In a scalar context, the function returns a sys_id.

my $sys_id = $incident->insert(
    short_description => $short_description,
    assignment_group => "Network Support",
    impact => 3);
print "sys_id=", $sys_id, "\n";

In a list context, the function returns a list of name/value pairs.

my %result = $incident->insert(
    short_description => $short_description,
    assignment_group => "Network Support",
    impact => 3);
print "number=", $result{number}, "\n";
print "sys_id=", $result{sys_id}, "\n";

You can also call it this way:

my %rec;
$rec{short_description} = $short_description;
$rec{assignment_group} = "Network Support";
$rec{impact} = 3;
my $sys_id = $incident->insert(%rec);

Note that for reference fields (e.g. assignment_group, assigned_to) you may pass in either a sys_id or a display value.

insertMultiple

This method inserts multiple records.

The input is an array of hash references. It returns an array of hash references.

This method requires installation of the ServiceNow Insert Multiple Web Services Plugin.

For additional information refer to the ServiceNow documentation on the "insertMultiple" Direct SOAP API method.

Syntax

my @results = $table->insertMultiple(@records);

Example

my $incident = $sn->table("incident");
my @allrecs;
foreach my $descr (@descriptions) {
    my $newrec = {
        short_description => $desc,
        assignment_group => $groupName,
        description => $desc,
        impact => 3};
    push @allrecs, $newrec;
}
my @results = $incident->insertMultiple(@allrecs);
foreach my $result (@results) {
    print "inserted ", $result->{number}, "\n";
}

update

This method updates a record. For information on available parameters refer to the ServiceNow documentation on the "update" Direct SOAP API method.

Syntax

$table->update(%parameters);
$table->update($sys_id, %parameters);

Note: If the first syntax is used, then the sys_id must be included among the parameters. If the second syntax is used, then the sys_id must be the first parameter.

For reference fields (e.g. assignment_group, assigned_to) you may pass in either a sys_id or a display value.

Examples

The following three examples are equivalent.

$incident->update(
    sys_id => $sys_id, 
    assigned_to => "5137153cc611227c000bbd1bd8cd2005",
    incient_state => 2);
    
$incident->update(
    sys_id => $sys_id, 
    assigned_to => "Fred Luddy", 
    incident_state => 2);

$incident->update($sys_id, 
    assigned_to => "Fred Luddy", 
    incident_state => 2);

query

This method creates a new Query object by calling "getKeys".

Syntax

my $query = $table->query(%parameters);
my $query = $table->query($encodedquery};

Example

The following example builds a list of all Incidents created between 1/1/2014 and 2/1/2014 sorted by creation date/time. The fetchAll method fetches chunks of records until all records have been retrieved.

my $filter = "sys_created_on>=2014-01-01^sys_created_on<2014-02-01";
my $qry = $sn->table("incident")->query(
    __encoded_query => $filter,
    __order_by => "sys_created_on");
my @recs = $qry->fetchAll();

getVariables

This method returns a list of hashes of the variables attached to a Requested Item (RITM).

Note: This function currently works only for the sc_req_item table.

Each hash contains the following four fields:

  • name - Name of the variable.

  • question - The question text.

  • reference - If the variable is a reference, then the name of the table. Otherwise blank.

  • value - Value of the question response. If the variable is a reference, then value will contain a sys_id.

  • order - Order (useful for sorting).

Syntax

$sc_req_item = $sn->table("sc_req_item");
@vars = $sc_req_item->getVariables($sys_id);

Example

my $sc_req_item = $sn->table("sc_req_item");
my $ritmRec = $sc_req_item->getRecord(number => $ritm_number);
my @vars = $sc_req_item->getVariables($ritmRec->{sys_id});
foreach my $var (sort { $a->{order} <=> $b->{order} } @vars) {
    print "$var->{name} = $var->{value}\n";
}

setDV

Used to enable (or disable) display values in queries. All subsequent calls to "get", "getRecords" or "getRecord" for this table will be affected. This method returns the modified Table object.

For additional information regarding display values refer to the ServiceNow documentation on "Return Display Value for Reference Variables".

Syntax

$table->setDV("true");
$table->setDV("all");
$table->setDv("");  # restore default setting

Examples

my $sys_user_group = $session->table("sys_user_group")->setDV("true");
my $grp = $sys_user_group->getRecord(name => "Network Support");
print "manager=", $grp->{manager}, "\n";

my $sys_user_group = $session->table("sys_user_group")->setDV("all");
my $grp = $sys_user_group->getRecord(name => "Network Support");
print "manager=", $grp->{dv_manager}, "\n";

setTimeout

Set the value of the SOAP Web Services client HTTP timeout. In addition, you may need to increase the ServiceNow system property glide.soap.request_processing_timeout.

Syntax

$table->setTimeout($seconds);

ServiceNow::SOAP::Query

Query objects and the related functions implement the ServiceNow's best practice recommendation for using Web Services to retrieve a large number of records.

A Query object is essentially a list of keys (sys_ids) for a particular table, and a pointer to the current position in that list. To construct a new Query object use the "query" or "asQuery" Table method.

  • "query" makes a Web Services call ("getKeys") to retrieve a list of keys.

  • "asQuery" simply converts an exsiting list of keys into a Query object.

Once the Query is constructed, the "fetch" and "fetchAll" functions can be used to get the actual records in chunks.

Example

This example illustrates the use of Query objects to traverse the cmdb_rel_ci table. The example involves two tables: cmdb_ci and cmdb_rel_ci.

my $cmdb_ci = $sn->table("cmdb_ci");
my $cmdb_rel_ci = $sn->table("cmdb_rel_ci");

We assume that $parentKey is the sys_id of a known configuration item. The objective is to print a list of all other configuration items on which this item immediately depends. In otherwords, all items which are one level downstream.

First we query cmdb_rel_ci to retrieve a list of records for which this item is the parent. @relData is this list of cmdb_rel_ci records.

my @relData = $cmdb_rel_ci->query(parent => $parentKey)->fetchAll();

Next we extract the child field from each of these cmdb_rel_ci records to create a new list of sys_ids

my @childKeys = map { $_->{child} } @relData;

@childKeys now contains a lists of sys_ids for configuration items. We convert this list of keys into a query object and fetch the records from the cmdb_ci table. If there are more than 250 records, fetchAll will loop internally until all records have been retrieved.

@childRecs = $cmdb_ci->asQuery(@childKeys)->fetchAll();
foreach my $childRec (@childRecs) {
    print $childRec->{name}, "\n";            
}

exclude

This method will affect any subsequent calls to "fetch". Any columns not specified in the argument(s) will be excluded from the returned result. By excluding unneeded columns from the query result, it is possible to significantly improve the performance of large queries. For a simpler way to achieve this objective, refer to the "include" method below.

You may pass this method either a list of column names, or a string containing a comma delimited list of names. It will override any prior calls to "exclude" or "include". It returns a reference to the modified Query object.

Syntax

$query->exclude(@list_of_columns);
$query->exclude($comma_delimited_list_of_columns);

fetch

Fetch the next chunk of records from a table. Returns a list of hashes.

This method calls "getRecords" to retrieve the records. An optional parameter allows specification of the number of records to be retrieved. If not specified, then the number of records will be based on the default chunk size for this Query object. If there are no remaining records, then an empty list will be returned.

Syntax

my @recs = $query->fetch();
my @recs = $query->fetch($numrecs);

Example

This example prints the names of all active users. Each call to "getRecords" returns up to 100 users.

my $query = $sn->table("sys_user")->query(active => "true", __order_by => "name");
while (@recs = $query->fetch(100)) {
    foreach my $rec (@recs) {
        print $rec->{name}, "\n";
    }
}

fetchAll

Fetch all the records in a Query by calling "fetch" repeatedly until there are no more records. Returns a list of hashes. In a scalar context it returns a reference to an array of hashes.

Syntax

my @recs = $query->fetchAll();
my @recs = $query->fetchAll($chunkSize);

Example

This example prints the names of all active users. Each call to "getRecords" returns up to 250 users since no chunk size was specified and the default is 250.

my @recs = $sn->table("sys_user")->query(active => "true", __order_by => "name")->fetchAll();
foreach my $rec (@recs) {
     print $rec->{name}, "\n";
}

getCount

This method returns the total number of keys in the Query.

getKeys

This method returns a list of the keys included in the Query.

Example

The following example calls "getKeys" to create a new query, and then makes of copy of the query using the same list of keys.

my $query1 = $table->query($encoded_query);
my $query2 = $table->asQuery($query1->getKeys());

include

This method will affect any subsequent calls to "fetch" by limiting which columns are returned. By including only the needed columns in the query result, it is possible to significantly improve the performance of large queries.

You may pass this method either a list of column names, or a string containing a comma delimited list of names. It will override any prior calls to "exclude" or "include". It returns a reference to the modified Query object.

For some reason the Direct Web Services API allows you to specify a list of columns to be excluded from the query result, but there is no similar out-of-box capability to specify only the columns to be included. This function implements the more obviously needed behavior by inverting the list. It uses the WSDL to generate a list of columns returned by "getRecords", and subtracts the specified names to create an "__exclude_columns" extended query parameter.

Syntax

$query->include(@list_of_columns);
$query->include($comma_delimited_list_of_columns);

Example

This example returns a list of all records in the cmdb_ci_computer table, but only 5 columns are returnd.

my $tbl = $sn->table("cmdb_ci_computer");
my $qry = $tbl->query()->include(
    qw(sys_id name sys_class_name operational_status sys_updated_on));
my @recs = $qry->fetchAll();    

setChunk

This method sets the default chunk size (number of records per fetch) for subsequent calls to "fetch" or "fetchAll". It returns a reference to the modified Query object.

If setChunk is not specified then the default is 250 records per fetch.

Syntax

$query->setChunk($numrecs);

Example

   my $rel_tbl = $sn->table("cmdb_rel_ci");
   my @rel_data = $rel_tbl->query()->setChunk(1000)->fetchAll();

DIAGNOSTICS

The fourth (optional) argument to the "ServiceNow" function is an integer trace level which can be helpful for debugging. Sometimes, when you are developing a new script, it seems to hang at a certain point, and you just want to know what it is doing. Set the trace level to 1 to enable tracing messages for SOAP calls. Set the trace level to 2 to dump the complete XML of all SOAP results. Set the trace level to 0 (default) to disable this feature.

You can also enable or disable tracing for a table by calling setTrace on the object.

$table->setTrace(2);

If you want even more, then add the following to your code. This will cause SOAP:Lite to dump the HTTP headers and contens for all messages, both sent and received.

SOAP::Lite->import(+trace => 'debug');

AUTHOR

Giles Lewis

ACKNOWLEDGEMENTS

Greg George, author of ServiceNow::Simple, from which a number of ideas were sourced.

LICENSE

This program is free software; you can redistribute it and/or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at:

http://www.perlfoundation.org/artistic_license_2_0

Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license.

If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license.

This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder.

This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed.

Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.