Skip to main content
Announcements
Join us at Qlik Connect for 3 magical days of learning, networking,and inspiration! REGISTER TODAY and save!

Qlik Sense: call Qlik Sense Engine API with Python

No ratings
cancel
Showing results for 
Search instead for 
Did you mean: 
Damien_V
Support
Support

Qlik Sense: call Qlik Sense Engine API with Python

Last Update:

Feb 23, 2021 4:08:26 AM

Updated By:

Sonja_Bauernfeind

Created date:

Jan 25, 2019 9:48:37 AM

This is a Python example to call the Qlik Sense Engine API.

Here is a simple script using the websocket-client module to call the Engine API. Note that the Qlik Sense virtual proxy is set to header authentication.

import websocket
import ssl
import json

header_user = {'header_user': 'user1'}

ws = websocket.create_connection("wss://qlikserver1.domain.local/hdr/app/", sslopt={"cert_reqs": ssl.CERT_NONE},header=header_user)

ws.send(json.dumps({
	"handle": -1,
	"method": "GetDocList",
	"params": [],
	"outKey": -1,
	"id": 1
}))

result = ws.recv()

while result:
    result=ws.recv()
    y = json.loads(result)
    print(y)

ws.close()


Example of results:

{'jsonrpc': '2.0', 'method': 'OnConnected', 'params': {'qSessionState': 'SESSION_CREATED'}}
{'jsonrpc': '2.0', 'id': 1, 'result': {'qDocList': [{'qDocName': 'test1', 'qConnectedUsers': 0, 'qFileTime': 0,
 'qFileSize': 176418, 'qDocId': '9b428869-0fba-4ba5-9f94-901ae2fdf041', 'qMeta': {'createdDate': '2018-11-29T09:28:40.588Z', 
'modifiedDate': '2018-12-17T15:13:56.860Z', 'published': True, 'publishTime': '2018-12-17T15:13:56.782Z', 
'privileges': ['read', 'offlineaccess'], 'description': '', 'dynamicColor': '', 'create': None, 'stream': {'id': 
'aaec8d41-5201-43ab-809f-3063750dfafd', 'name': 'Everyone'}, 'canCreateDataConnections': False}, 'qLastReloadTime': 
'2018-11-29T09:30:42.121Z', 'qTitle': 'test1', 'qThumbnail': {}}]}}


 

Labels (1)
Comments
beatYesterday
Contributor III
Contributor III

All,


After further research and trial and error I was able to figure out how to do this.  I'm adding the general code of how I did this below for others' reference.

 

createSessionURL = "https://host/qps/session?xrfkey=1234567890123457"

postHeaders={   "X-Qlik-User": "UserDirectory=<DIRECTORY>;UserId=<USER>",
            "X-Qlik-XrfKey": "1234567890123457",
            "Content-type":"application/json"
        }

body ="""
{
  "UserDirectory": "<DIRECTORY>",
  "UserId": "<USER>",
  "Attributes": [ ],
  "SessionId": "11111111"
}
"""

#CREATE A SESSION OBJECT
s = requests.Session()

#use created session ID to get output of Engine API exportData function, this returns a session object with the sessionID you define
r = s.post(createSessionURL, headers= postHeaders, cert =(pemPath,pemKeyPath), verify=False, allow_redirects=True, data=body)

#set headers
getHeaders = {   "X-Qlik-User": "UserDirectory=<DIRECTORY>;UserId=<USER>",
            "X-Qlik-XrfKey": "1234567890123457",
            "X-Qlik-Session": "11111111"
        }

csvURL = "https://host/tempcontent/<randomlyGeneratedPath>.csv?serverNodeId=<SERVERNODE>&xrfkey=1234567890123457'

#set Qlik Session Cookie with the same sessionID defined in post requests
s.cookies.set("X-Qlik-Session", '11111111', domain = <qlikHostDomain>)

#make call for file
r2 = s.get(csvURL, headers= getHeaders, cert =(pemPath,pemKeyPath), verify=False, allow_redirects=True)
su_
Contributor
Contributor

Can you also give an example in Qlik Sense Desktop? 

Sonja_Bauernfeind
Digital Support
Digital Support

Hello @su_ 

The same example applies to Qlik Sense Desktop. See Connecting to the Qlik Engine JSON API.

What will change is:

Qlik Sense Enterprise: wss://server.domain.com:4747/app/ or wss://server.domain.com[/virtual proxy]/app/

Qlik Sense Desktop: ws://localhost:4848/app/

All the best,
Sonja 

su_
Contributor
Contributor

Hello @Sonja_Bauernfeind

I wrote this code to submit 2 API requests

  1. Connecting to a Qlik Sense dashboard
  2. Creating a dimension in that dashboard

I was able to get proper responses from the Qlik server for each API request, but the dimension was never created. I wonder if you would have any clue? See codes and responses below

Code: 

import websockets
import json
import asyncio
import time

url = "ws://localhost:4848/app/"

req_open_doc = {
    "method": "OpenDoc",
    "handle": -1,
    "params": [
        "C:\\Users\\my_directory\\my_dashboard.qvf"
    ],
  "id": 1,
  "outKey": -1,
}

req_create_dim = {
    "jsonrpc": "2.0",
    "handle": 1,
    "id": 2,
    "method": "CreateDimension",
    "params": {
        "qProp": {
            "qInfo": {
                "qId": "aaaaa",
                "qType": "dimension"
            },
            "qDim": {
                "qGrouping": 'N',
                "qFieldDefs": [
                    "AAC-VERSION PACKAGES"
                ],
                "qFieldLabels": [
                    ""
                ],
                "qLabelExpression": ""
            },
            "qMetaDef": {
                "title": "HelloFeature",
                "description": "",
                "tags": [
                    "group_HeyFeatureGroup"
                ]
            }
        }
    }
}

async def call_api():
    async with websockets.connect(url) as ws:
        await ws.send(json.dumps(req_open_doc))

        result = await ws.recv()
        print(result)
        result = await ws.recv()
        print(result)

        await ws.send(json.dumps(req_create_dim))
        result = await ws.recv()
        print(result)
        # result = await ws.recv()
        # print(result)

asyncio.get_event_loop().run_until_complete(call_api())

Response: 

{"jsonrpc":"2.0","method":"OnConnected","params":{"qSessionState":"SESSION_CREATED"}}
{"jsonrpc":"2.0","id":1,"result":{"qReturn":{"qType":"Doc","qHandle":1,"qGenericId":"C:\\my_directory\\my_dashboard.qvf"}},"change":[1]}
{"jsonrpc":"2.0","id":2,"result":{"qReturn":{"qType":"GenericDimension","qHandle":2,"qGener
Sonja_Bauernfeind
Digital Support
Digital Support

Hello @su_ 

If you require assistance troubleshooting custom code, please post your question directly in the relevant forum: Integration, Extensions & APIs. If you need direct engagement from Qlik to assist you, I would recommend our Professional Services.

All the best,
Sonja 

 

olaoyesunday1
Contributor III
Contributor III

Hi All, I am trying to use webscocket Api to connect Qlik Cloud , to pull a table from the cloud and to convert it to the Dataframe panda but I am having issue. It was connecting to the cloud but could not pull the table to my jupyter notebook. here is the code:

 

import asyncio
import websockets
import json
import pandas as pd
import nest_asyncio

# Apply the nest_asyncio patch
nest_asyncio.apply()

# Configuration
qlikcloud_url = "wss://mytenant.eu.qlikcloud.com//app/f5555629-bb12-4983-854b-1ed7c9682f55"
api_key = "api key"
app_id = "f5555629-bb12-4983-854b-1ed7c9682f55"
table_object_id = 'ZgGPbV'

async def get_table_data():
    async with websockets.connect(
        qlikcloud_url,
        extra_headers={
            "Authorization": f"Bearer {api_key}"
        }
    ) as websocket:
        # Open the app
        open_doc_request = {
            "jsonrpc": "2.0",
            "id": 1,
            "method": "OpenDoc",
            "handle": -1,
            "params": {
                "qDocName": app_id,
                "qNoData": True
            }
        }
        await websocket.send(json.dumps(open_doc_request))
        response = await websocket.recv()
        open_doc_response = json.loads(response)
        print(f"Open Doc Response: {open_doc_response}")

        # Check if the 'result' key is in the open doc response
        if 'result' in open_doc_response:
            doc_handle = open_doc_response['result']['qReturn']['qHandle']
            print(f"Document Handle: {doc_handle}")

            # Get the object handle
            get_object_request = {
                "jsonrpc": "2.0",
                "id": 2,
                "method": "GetObject",
                "handle": doc_handle,
                "params": {
                    "qId": table_object_id
                }
            }
            await websocket.send(json.dumps(get_object_request))
            response = await websocket.recv()
           get_object_response = json.loads(response)
            print(f"Get Object Response: {get_object_response}")

            if 'result' in get_object_response:
                object_handle = get_object_response['result']['qReturn']['qHandle']
                print(f"Object Handle: {object_handle}")

                # Get the layout of the object
                get_layout_request = {
                    "jsonrpc": "2.0",
                    "id": 3,
                    "method": "GetLayout",
                    "handle": object_handle,
                    "params": {}
                }
                await websocket.send(json.dumps(get_layout_request))
                response = await websocket.recv()
                layout_response = json.loads(response)
                print(f"Table Layout: {layout_response}")

                # Check if the 'result' key is in the layout response
                if 'result' in layout_response and 'qLayout' in layout_response['result']:
                    qLayout = layout_response['result']['qLayout']

                    # Send request to get table data
                    get_data_request = {
                        "jsonrpc": "2.0",
                        "id": 4,                                      "method": "GetHyperCubeData",
                        "handle": object_handle,
                        "params": {
                            "qPath": "/qHyperCubeDef",
                            "qPages": [{"qTop": 0, "qLeft": 0, "qHeight": 1000, "qWidth": 10}]
                        }
                    }
                    await websocket.send(json.dumps(get_data_request))
                    response = await websocket.recv()
                    table_data_response = json.loads(response)
                    print(f"Table Data: {table_data_response}")

                    # Check if 'result' key is in the table data response
                    if 'result' in table_data_response:
                        table_data = table_data_response['result']['qDataPages'][0]
                        print(f"Table Data Pages: {table_data}")

                        rows = table_data['qMatrix']
                        columns = qLayout['qHyperCube']['qDimensionInfo'] + qLayout['qHyperCube']['qMeasureInfo']

                        parsed_data = []
                        for row in rows:
                            parsed_row = {}
                            for col, value in zip(columns, row):                                                                    parsed_row[col['qFallbackTitle']] = value['qText']
                            parsed_data.append(parsed_row)

                        # Convert to DataFrame
                        df = pd.DataFrame(parsed_data)
                        print(df)

                        # Optionally save to CSV
                        df.to_csv("qlikcloud_table_data.csv", index=False)
                    else:
                        print("Error: 'result' key not found in table data response.")
                else:
                    print("Error: 'qLayout' key not found in layout response.")
            else:
                print("Error: 'result' key not found in GetObject response.")
        else:
            print("Error: 'result' key not found in OpenDoc response.")
            print(f"Full OpenDoc Response: {open_doc_response}")

# Run the async function
asyncio.get_event_loop().run_until_complete(get_table_data())

 

but I keep on getting this error:

 

pen Doc Response: {'jsonrpc': '2.0', 'method': 'OnConnected', 'params': {'qSessionState': 'SESSION_ATTACHED'}}
Error: 'result' key not found in OpenDoc response.
Full OpenDoc Response: {'jsonrpc': '2.0', 'method': 'OnConnected', 'params': {'qSessionState': 'SESSION_ATTACHED'}}

 

 

Contributors
Version history
Last update:
‎2021-02-23 04:08 AM
Updated by: