Managing Qlik Cloud with Python and Qlik SDK

Accessing the Qlik API using the Python requests library quite straight forward although soon some code can start to become complex. Such as using OAuth to connect and if you’re using multiple tenants using the regional authentication rather than per tenant is a must!

Qlik has kindly packaged their API’s into a Python Library Qlik SDK (Software Development Kit) . This, should, help you work faster developing your scripts to manage your Qlik Cloud estate

The Qlik SDK code documentation is here https://pypi.org/project/qlik-sdk/

python3 -m pip install --upgrade qlik-sdk

Once you have installed the package to Ubuntu you can leverage the modules within to connect and control your Qlik Cloud Tenants. I must say the documentation above isn’t great and I’ve no idea why they don’t include examples in the API documentation (along with CLI, Curl, and Node) ? That said because you can view the raw code it becomes very helpful as the comments there help you understand what’s going on.

Getting it to work…

There are a number of help sites I visited when trying an initial handshake with my Qlik Tenant using OAuth. However, I found myself constantly unable to connect. Creating an OAuth token on the tenant and following the code snippet here to the letter https://qlik.dev/examples/authenticate-examples/py-oauth-m2m-connect/

To finally resolve the issue I had to go into the Qlik-Sdk python files to print out the progress. One thing they don’t seem to mention is that if Scope if omitted then it will add ‘user_default’. Annoyingly that was one I hadn’t selected because in https://qlik.dev/authenticate/oauth/scopes/ the advice is not to use it…

Scope is actually a list. Again not clear but if you want to add additional scopes use the following syntax with a comma between the strings:

scope=["admin_classic"]

user default is always added so the params you’re actually passing are:

I did a test where I’d disabled ‘user_default’ and it worked. So if you have at least one scope enabled it shouldn’t error. The other thing to note is if you use a regional OAuth rather than a tenant (if you’re able to) the above error wont be an issue to you.

One of the many fun things whilst you try and get your head around it if you’re not a seasoned Python coder…


Submitting a Post and Get to the API

The rest class allows me to Get, Send, Put, etc. information to the Qlik API. Once you have authorized your client you can begin. (https://qlik.dev/apis/). You can also use other classes such as Qlik, but for now we’ll focus on rest.

Set up your client as per the instructions https://qlik.dev/examples/authenticate-examples/py-oauth-m2m-connect/

...
# authorize the client configuration with your Qlik Cloud tenant
client.authorize()

# call the /users/me rest endpoint with the client configuration
response = client.rest(path="/users/me").json()
print(json.dumps(response, indent=4, separators=(". ", " = ")))

(for this code to work you have to ‘import json’ into the python code.)

You can specify params when getting information to limit what is returned, for example here I’m only interested in the managed spaces:

...
#Sending params to the API request
payload={'type':'managed'}
response = client.rest(path="/spaces", method="get",params=payload).json()
print(json.dumps(response, indent=4, separators=(". ", " = ")))

When your sending (Posting) information to the API use the post method, you have to pass your payload to data (not params as before). Here I’m creating a new shared space:

...
# posting to a client, we now use data rather than params.
payload={'name':'I did this using the Region OAuth twice','type':'shared','description':'Long Description here'}
response = client.rest(path="/spaces", method="post", data=payload).json()
print(json.dumps(response, indent=4, separators=(". ", " = ")))

Finally we can use combinations of this approach, along with conditional functions within python to test if a space exists. If it doesn’t exist we will create it, if it does then we will modify the description using a Put request…

...
#Sending params to the API request to look for a space name
payload={'name':space_name}
response = client.rest(path="/spaces", method="get",params=payload).json()
    
print(json.dumps(response, indent=4, separators=(". ", " = ")))
print('------------------------------------------------------')

if len(response["data"]) == 1:
    print('The Space Exists: ', space_name, ' Updating the description')
    workable_data = response["data"] 
    space_id = workable_data[0]["id"]
    print('The space id is ', space_id)

    payload={'description':'We are changing the description'}
    response = client.rest(path="/spaces/" + space_id, method="put", data=payload).json()   
         
elif len(response["data"]) > 1:
    print('Error, We have had multiple lines returned for ', space_name ) # The name past is a Case-insensitive open search with wildcards both as prefix and suffix. For example, "?name=fin" will get "finance", "Final" and "Griffin".
    exit()
else:
    print('The Space does not exist')
    # posting to a client, we now use data rather than params.
    payload={'name':space_name,'type':'shared','description':'Long Description here'}
    response = client.rest(path="/spaces", method="post", data=payload).json()

Happy Qliking!

Leave a comment