Introduction
At AutoCon2, I shared Armstrong’s automation journey and how leveraging Itential has accelerated the delivery of our automations. Reflecting on the presentation, I realized it would be valuable to dive deeper into where our journey began. In this blog series, we’ll explore how we started automating the fulfillment of ServiceNow requests. From tackling the basics of ServiceNow APIs to fulfilling requests using other system’s APIs, this series will provide insights and actionable steps to help you begin your own automation journey. In this first blog, we’ll go through the basics of using the ServiceNow API via Python, and how it can be used to get data out of ServiceNow.
Note: You can spin up your own ServiceNow instance for testing by going to the ServiceNow developer portal and signing up for a free account.
Navigating the ServiceNow Table API
You’ll first need to ensure that you have the Python modules requests & python-dotenv modules installed. You can install these via command line using pip:
pip install requests python-dotenv
Once those modules are installed, we can build our first API call into ServiceNow. Our first call will be to grab a list of active incidents assigned to a specific assignment group. But first, there are a few components that we have to map out in order to build the call. First, we’ll need the authentication components: SerivceNow instance, username, & password. We’ll use the python-dotenv module to import values from a .env file. The .env file will look like this:
INSTANCE=".service-now.com"
USERNAME="test_user"
PASSWORD="test_password"
This is how to use the contents of the .env file in your script:
load_dotenv()
instance = os.getenv('INSTANCE')
username = os.getenv('USERNAME')
password = os.getenv('PASSWORD')
Next, we need to set the base URL for the API call. This will give us a variable we can reuse as we continue making calls into ServiceNow. We’ll use a Python F string to concatenate our instance into the URL string:
base_url = f'https://{instance}/api/now/table'
Next, we’ll add the incident table name to the base_url variable to get our complete URI for the API call:
uri = f'{base_url}/incident'
Next, we’ll set our headers and ensure we get JSON back from ServiceNow:
headers = {"Accept": "application/json"}
Before we can make the API call, we need to set our query parameters. Here are the two main parameters to be aware of:
- sysparm_query allows you to filter the records returned by your API call using ServiceNow’s encoded query syntax. For example, you can use sysparm_query=state=1 to retrieve only records where the state field is set to “1” (typically representing “New” in the incident table). This parameter is essential for narrowing down results to exactly what you need and improving the performance of your requests.
- sysparm_fields specifies which fields to include in the API response. Instead of returning all fields for each record, you can use sysparm_fields=number,short_description to retrieve only the record number and short description fields. This reduces the amount of data transferred, making the response easier to parse and the request more efficient.
For our testing, we’ll use the following params:
assignment_group = "Automation Testing"
params = {
'sysparm_fields': 'number,assignment_group,short_description',
'sysparm_query': f'assignment_group.name={assignment_group}^active=true'
}
Now we can make our API call. We’ll use the requests.get method and pass in the variables from above, as well as our authentication parameters. We’ll assign the response to a variable called response:
response = requests.get(uri, auth=(username,password), headers=headers, params=params)
We can access the JSON object that was returned with the response by calling response.json(). We’ll overwrite the value of the response variable with the returned JSON object. We’ll also print out a “pretty” version of the object to view the data:
response = response.json()
print(json.dumps(response, indent=2))
And here the result:
{
"result": [
{
"number": "INC0009009",
"short_description": "Unable to access the shared folder.",
"assignment_group": {
"link": "https://instance.service-now.com/api/now/table/sys_user_group/6ad6b94253061210f94851a0a0490edf",
"value": "6ad6b94253061210f94851a0a0490edf"
}
},
{
"number": "INC0009005",
"short_description": "Email server is down.",
"assignment_group": {
"link": "https://instance.service-now.com/api/now/table/sys_user_group/6ad6b94253061210f94851a0a0490edf",
"value": "6ad6b94253061210f94851a0a0490edf"
}
}
]
}
As you can see, two different incidents were returned: INC0009009 & INC0009005. Because of our sysparm_fields query parameter, only the number, short_desription, and assignment_group fields were returned. But now that we have the data, we can iterate on it and take any actions that we see fit. To put it all together, here is the entire script that we built out:
import requests
import json
import os
from dotenv import load_dotenv
if __name__ == '__main__':
load_dotenv()
instance = os.getenv('INSTANCE')
username = os.getenv('USERNAME')
password = os.getenv('PASSWORD')
base_url = f'https://{instance}/api/now/table'
uri = f'{base_url}/incident'
headers = {"Accept": "application/json"}
assignment_group = "Automation Testing"
params = {
'sysparm_fields': 'number,assignment_group,short_description',
'sysparm_query': f'assignment_group.name={assignment_group}^active=true'
}
response = requests.get(uri, auth=(username,password), headers=headers, params=params)
response = response.json()
print(json.dumps(response, indent=2))
Conclusion & Next Topic
In this blog, we covered the basics for accessing the SerivceNow API. We made a get request to grab a subset of incidents using the sysparm_query parameter, and we were able to view the data that was returned.
In the next blog, we will build on this foundation and start to build out the code to automate the fulfillment of ServiceNow requests. We will cover how to get tasks assigned to a certain group, and how to traverse the ServiceNow table structure to find the variables associated with a task. Stay tuned, you won’t want to miss it!