• First Steps
  • Basic Data Operations
  • Creating Action Handlers using Action API
  • Developing a Connector
  • Working with Automation Tasks

Overview

In this tutorial, we make first contact with the HIRO API. We will understand which prerequisites are required to use the API, authenticate with our credentials, and the make first calls to the HIRO API.

We will perform the following steps to implement the connector:

  1. Prepare prerequisites to connect with HIRO

  2. Authenticate and retrieve an auth token

  3. Call the HIRO API to retrieve data

The sample code in this tutorial is written in Python programming language. However, the HIRO API follows web standards and therefore is language agnostic. You may use any programming language of your choice to interact with the HIRO API. We are using Jupyter to write the sample code to facilitate iterating and testing the code snippets (see screenshot below).

Jupyter notebook
Figure 1. A Jupyter notebook to quickly iterate code samples

Prepare prerequisites to connect with HIRO

Before we can start, there are a few prerequisites we need to prepare:

  1. Make sure that you have access to a HIRO instance. The HIRO URL should be https://core.arago.co/api/

  2. Make sure that you have a valid user account and password with sufficient access permissions.

  3. Make sure that you have received a registered application key (pair of client_id and client_secret)

  4. Ideally you have an id for the 'data-scope' (environment) you want to interact with. If omitted the default scope of your account will be used. Please be aware, that this may lead to confusion if your account has access to multiple scopes. Therefore, it’s highly recommended defining your desired scope.

Connectors typically use service accounts to connect with HIRO. However, you may work with your personal HIRO user account during development.

To connect and authenticate ourselves with the HIRO system, we need to provide a few parameters, i.e. server URL, user credentials and application credentials. For convenience and to keep credentials out of our code, we put them into a configuration file 'hiro_credentials.json', so that we can read the configuration from file later.

hiro_credentials.json
{
  "api_url": "https://core.arago.co/api/",
  "scope" : "--INSERT SCOPE ID HERE--",
  "client_id": "--INSERT CLIENT ID HERE--",
  "client_secret": "--INSERT CLIENT SECRET HERE--",
  "username": "--INSERT YOUR USER NAME HERE--",
  "password": "--INSERT YOUR PASSWORD HERE--"
}

Authenticate and retrieve an auth token

Now we can import the credentials file, so that server URL and user credentials are available as variables. For convenience, we construct additional specific URLs for the Auth API (hiro_auth_api) and Graph API (hiro_auth_api).

# Imports
import requests
import json
import pprint
pp = pprint.PrettyPrinter(indent=4)

# Create HIRO Session
hiro_credentials_file = "./hiro_credentials.json" #
with open(hiro_credentials_file) as json_file:
    hiro_credentials = json.load(json_file)
hiro_api_base = hiro_credentials['api_url']
hiro_auth_api = hiro_api_base + 'auth/6/'
hiro_graph_api = hiro_api_base + 'graph/7/'

As next step, we need to authenticate with the HIRO server. This is done by sending a POST request to the Auth API, and sending the auth data as payload attributes. We must provide our user name, password, client id and client secret to successfully authenticate. The generated user token is then bound to the provided user account in combination with the specific application (client_id).

# Authenticate
print('Authenticating with HIRO Auth Service to receive an auth token ...')
auth_data = {'client_id': hiro_credentials['client_id'], 'client_secret': hiro_credentials['client_secret'], 'username': hiro_credentials['username'], 'password': hiro_credentials['password']}
response = requests.post(hiro_auth_api+'app', data=json.dumps(auth_data))

After we have sent the authentication request, we want to know whether the authentication has succeeded, and react accordingly. In our sample code, we will print out the authentication status to the console.

For further API use, we always need to pass on our auth token as header attribute in all HTTPS requests. We will prepare for that by creating a session object and add the header attribute to it. From now on, all requests in this session will automatically send the auth token.

# Inspect response
print('Response code: ' + str(response))
if response.ok:
    hiro_user_token = response.json()['_TOKEN']
    s = requests.Session()
    s.headers.update({'Authorization': 'Bearer ' + hiro_user_token})
    print ('You have successfully created a HIRO access token and can start using the HIRO API.')
else:
    print ('Authentication error: '+ str(response.status_code) + ' - ' + response.reason)
    print ('Error message: ' + response.text)
    print ('Please check your credentials and try again.')

The console output should look like this:

Authenticating with HIRO Auth Service to receive an auth token ...
Response code: <Response [200]>
You have successfully created a HIRO access token and can start using the HIRO API.

If everything went well, we have a valid authentication token, created an HTTPS session, and are ready to work with the HIRO API. If not, there was probably something wrong with your credentials. Go back, check the credentials, and retry.

Refactoring the session initiation

Before we continue, let’s refactor the authentication code, so that it will be reusable for further examples. We define a function for session initiation, which takes the file name of the credentials file as input parameter. The returned session object will contain the HTTPS session, the HIRO URLs and the scope.

# Define authentication function
def initiate_hiro_session(credentials_file_name):
    with open(credentials_file_name) as json_file:
        hiro_credentials = json.load(json_file)
    hiro_session_context = dict()
    hiro_api_base = hiro_credentials['api_url']
    hiro_session_context['scope'] = hiro_credentials['scope']
    hiro_session_context['auth_api'] = hiro_api_base + 'auth/6/'
    hiro_session_context['graph_api'] = hiro_api_base + 'graph/7/'

    # authenticate
    print('Authenticating with HIRO Auth Service to receive an auth token ...')
    auth_data = {'client_id': hiro_credentials['client_id'], 'client_secret': hiro_credentials['client_secret'],
                 'username': hiro_credentials['username'], 'password': hiro_credentials['password']}
    hiro_auth_api = str(hiro_session_context['auth_api'])
    print(hiro_auth_api)
    response = requests.post(hiro_auth_api + 'app', data=json.dumps(auth_data))

    print('Response code: ' + str(response))
    if response.ok:
        print('You have successfully created a HIRO access token and can start using the HIRO API.')
        hiro_user_token = response.json()['_TOKEN']
        hiro_session_context['session'] = requests.Session()
        hiro_session_context['session'].headers.update({'Authorization': 'Bearer ' + hiro_user_token})
        hiro_session_context['active'] = True
    else:
        print('Authentication error: ' + str(response.status_code) + ' - ' + response.reason)
        print('Error message: ' + response.text)
        print('Please check your credentials and try again.')
        hiro_session_context['active'] = False

    return hiro_session_context


hiro_session = initiate_hiro_session('./hiro_credentials.json')
if hiro_session['active'] == True:
    print('continue using the API ...')

Call the HIRO API to retrieve data

With this active HIRO session, we can now work with the HIRO API. As an example, we will try to submit a simple query to the HIRO Graph.

The HIRO Graph supports different query modes. We use the vertices query mode to search for items of type ogit/Automation/AutomationIssue. Don’t worry, we will explain this data type later in details.

As you may have noticed, we need to escape a few special characters in the query string before sending it as URL query parameter.

vertex_query_url = hiro_session['graph_api'] + 'query/vertices?query='
query_string = '+ogit/_type:ogit/Automation/AutomationIssue AND ogit/_scope:'+hiro_session['scope']
escaped_query_string = query_string\
    .replace('/', '%5C%2F')\
    .replace(' ', '%20')\
    .replace('\\', '%5C')\
    .replace(':','%3A')\
    .replace( '+', '%2B')

query_response = hiro_session['session'].get(vertex_query_url + escaped_query_string)
print(query_response)
pp.pprint(query_response.json())

This query has either returned a list of AutomationIssue vertices - if you already have some in your HIRO instance - or alternatively an empty list. In case your Graph is still empty: we will soon learn how to populate it with data.

The result data might look like this:

{
  "items": [
    {
      "/DatePrintOutput": "2020-08-18 13:23:30",
      "ogit/Automation/deployStatus": "deployed",
      "ogit/Automation/issueType": "unknown",
      "ogit/Automation/originNode": "ckd73u0ul04jo01100j5dppq7_ckdzyc2kftth40126ws47ktio",
      "ogit/Automation/processingTimestamp": "1597757010332",
      "ogit/_created-on": 1597757000390,
      "ogit/_creator": "cjy5tvdfx0nkq1o7040e4mow0_cjl7za8hs3csfl1756lo90sen",
      "ogit/_creator-app": "cju16o7cg0001mz775fnoq66i_cjix82rxi000gu473w5kvkpqv",
      "ogit/_graphtype": "vertex",
      "ogit/_id": "ckd73u0ul04jo01100j5dppq7_ckdzz9jnqxrya0185e1e4zijb",
      "ogit/_is-deleted": false,
      "ogit/_modified-by": "cjy5tvdfx0nkq1o7040e4mow0_ckd73u30p04k00110vtx04pgg",
      "ogit/_modified-by-app": "cju16o7cf0000mz77pbwbhl3q_cjix82tev000ou473gko8jgey",
      "ogit/_modified-on": 1597757011631,
      "ogit/_organization": "cjy5tvdfx0nkq1o7040e4mow0_cjy5tvdfx0nku1o70n01y50gw",
      "ogit/_owner": "cjy5tvdfx0nkq1o7040e4mow0_cjy5tvdfx0nks1o70ouhlsk6a",
      "ogit/_scope": "cjy5tvdfx0nkq1o7040e4mow0_ckd73u0ul04jo01100j5dppq7",
      "ogit/_type": "ogit/Automation/AutomationIssue",
      "ogit/_v": 4,
      "ogit/_v-id": "1597757011631-SwG5pa",
      "ogit/status": "RESOLVED",
      "ogit/subject": "Test"
    },
    {
      "/ProcessIssue": "todo",
      "ogit/Automation/deployStatus": "ExecIdle threshold (900) exceeded: more knowledge required?",
      "ogit/Automation/issueType": "unknown",
      "ogit/Automation/originNode": "ckd73u0ul04jo01100j5dppq7_ckdzyc2kftth40126ws47ktio",
      "ogit/Automation/processingTimestamp": "1597756624025",
      "ogit/_created-on": 1597755613445,
      "ogit/_creator": "cjy5tvdfx0nkq1o7040e4mow0_cjl7za8hs3csfl1756lo90sen",
      "ogit/_creator-app": "cju16o7cg0001mz775fnoq66i_cjix82rxi000gu473w5kvkpqv",
      "ogit/_graphtype": "vertex",
      "ogit/_id": "ckd73u0ul04jo01100j5dppq7_ckdzyfthhtuci01263h47hpo9",
      "ogit/_is-deleted": false,
      "ogit/_modified-by": "cjy5tvdfx0nkq1o7040e4mow0_ckd73u30p04k00110vtx04pgg",
      "ogit/_modified-by-app": "cju16o7cf0000mz77pbwbhl3q_cjix82tev000ou473gko8jgey",
      "ogit/_modified-on": 1597756624107,
      "ogit/_organization": "cjy5tvdfx0nkq1o7040e4mow0_cjy5tvdfx0nku1o70n01y50gw",
      "ogit/_owner": "cjy5tvdfx0nkq1o7040e4mow0_cjy5tvdfx0nks1o70ouhlsk6a",
      "ogit/_scope": "cjy5tvdfx0nkq1o7040e4mow0_ckd73u0ul04jo01100j5dppq7",
      "ogit/_type": "ogit/Automation/AutomationIssue",
      "ogit/_v": 5,
      "ogit/_v-id": "1597756624107-zXxQk6",
      "ogit/status": "STOPPED",
      "ogit/subject": "Test"
    }
  ]
}

or an empty list:

{
    "items": []
}

Summary

Congratulations! You have successfully connected to HIRO and run the first query against the graph database.

In this tutorial, we have prepared the prerequisites to work with the HIRO API, authenticated with the Auth API, and then used the auth token to submit a query to the HIRO Graph.

In the next tutorial, we will learn how to Write and read data to the HIRO Graph.