Connecting to the Qlik Engine JSON API
To use the Qlik Engine JSON API, you need to open a WebSocket to the engine. There are differences in how you do this, depending on whether you are working with Qlik Sense Enterprise or Qlik Sense Desktop.
To open a WebSocket to the engine, use one of the following URIs:
-
Qlik Sense Enterprise: wss://server.domain.com:4747/app/ or wss://server.domain.com[/virtual proxy]/app/
-
Qlik Sense Desktop: ws://localhost:4848/app/
When you connect to the engine, you establish an engine session, which consists of one user and one app. You can optionally append the app identifier (the GUID in Qlik Sense Enterprise or the app name in Qlik Sense Desktop) to the URI you use to open the Websocket. Supplying the app identifier serves two purposes:
- In a multi-node environment, the Proxy server uses the app GUID to route your request to the appropriate server. We recommend that you append the app GUID to the WebSocket URI in a multi-node environment.
- The Qlik associative engine uses the app identifier to establish your engine session (if an app identifier is not specified, the engine session is established using a virtual app). For example, if a user attempted to open two WebSocket connections to the same app, only the first WebSocket would be able to call the OpenDoc method. The second would receive an error message saying App already open.
The app identifier in the URI simply indicates which app you plan to open. Whether or not you specify an app identifier, you can call only methods from the Global class until you call the openDoc method (at which point you can also call methods from the App class). There is nothing preventing you from opening a WebSocket using one app, and then calling the OpenDoc method on a different app.
A single WebSocket connection can be associated with only one engine session (consisting of the app context plus the user). If you need to work with multiple apps, you must open a separate WebSocket for each one.
Qlik Sense Desktop
After you launch Qlik Sense Desktop and log in, you can connect to the Qlik Engine JSON API using the following URI:
For example, using JavaScript in a browser, make the following call:
This opens a WebSocket that is scoped to the global context, which means you can use only methods that belong to the Global class. For example, you could send a call to the GetDocList method to retrieve a list of all apps:
{
"jsonrpc": "2.0",
"id": 0
"handle": -1,
"method": "GetDocList",
"params": [],
}
To work directly with a particular app, you need to call the OpenDoc method for that app. Assuming we have an app called "Consumer Sales.qvf" in the default file location, we could send the following request:
{
"jsonrpc": "2.0",
"id": 2,
"method": "OpenDoc",
"handle": -1,
"params": [
"C:\\Users\\myuser\\Documents\\Qlik\\Sense\\Apps\\Consumer Sales.qvf"
]
}
The engine returns the following response:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"qReturn": {
"qType": "Doc",
"qHandle": 1
}
}
}
The handle of 1 indicates that our connection now has the app context. At this point we can use methods from the App class, and other classes as we continue to work with objects within the app.
If you know you want to perform operations on an app, you can add the app's path (URL encoded) to the URI:
For example, to open a connection scoped to the Consumer Sales.qvf app context, use the following URI:
You must still call the OpenDoc method on this app to call methods from the App class.
Qlik Sense Enterprise
If you are working with Qlik Sense Enterprise, you (or your user) must be authenticated before opening a WebSocket to the Qlik Engine JSON API. Authentication can be performed in several ways, depending on how your installation is configured and where the code that is interacting with the Qlik Engine JSON API is running:
- If your code is running on a trusted computer, you can use certificate authentication. You need to export the certificates from QMC and copy them to the computer where your code will run. For more information, see Exporting certificates.
- If your code is running in a browser, or the certificates are not available, you must authenticate via the Qlik Sense Proxy Service. If the user is not authenticated, the Qlik Sense Proxy Service redirects the request to the authentication module (which can be configured in a number of ways). For more information about the authentication process, see Communicating with Qlik Sense.
Qlik Sense verifies the origin of every WebSocket request against the Host white list in the QMC. Make sure that any service you build has its origin listed in the white list of the virtual proxy. You may also need to add an Access-Control-Allow-Origin header in the Additional response headers field.
You can connect to the Qlik Engine JSON API using the following WebSocket URIs:
- wss://server.domain.com:4747/app/ (connect directly to the Qlik Engine JSON API; requires certificates)
- wss://server.domain.com[/virtual proxy]/app/ (connect via the Qlik Sense Proxy Service)
These URIs will result in a WebSocket that is opened with global context (that is, you will be able to call only methods from the Global class). In a multi-node environment, we recommend that you append the app GUID to the URI.
Example 1: Connect directly to Qlik Engine JSON API using certificates
Let's look at a Node.js example where we connect directly to the engine, using certificate authentication and a built-in user. The ws library opens a WebSocket using a configuration that specifies the URI, the location of the certificates, and the user name and password. Other settings can be added to the configuration as well (see the ws documentation for details).
const WebSocket = require('ws');
...
// Set certPath to the path to the directory that contains the exported client certificates in PEM format.
var certPath = path.join('C:', 'ProgramData', 'Qlik', 'Sense', 'Repository', 'Exported Certificates', '.Local Certificates');
var certificates = {
cert: fs.readFileSync(path.resolve(certPath, 'client.pem')),
key: fs.readFileSync(path.resolve(certPath, 'client_key.pem')),
root: fs.readFileSync(path.resolve(certPath, 'root.pem'))
};
// Open a WebSocket using the engine port (rather than going through the proxy)
// We use the certificates and a built-in Qlik service account
// We connect at the global level, which gives access to APIs in the Global class
const ws = new WebSocket('wss://server.domain.com:4747/app/', {
ca: [certificates.root],
cert: certificates.cert,
key: certificates.key,
headers: {
'X-Qlik-User': 'UserDirectory=internal; UserId=sa_engine'
}
});
ws.onopen = function (event) {
// send some message
}
Assuming this code runs successfully, we now have a WebSocket that is bound to the global object. At this point, we can call only methods in the Global class.
Let's make a call to the GetDocList method:
var msg = {
"jsonrpc": "2.0",
"id": 1,
"method": "GetDocList",
"handle": -1,
"params": []
}
ws.send(JSON.stringify(msg));
// Receive the response
ws.onmessage = function (event) {
console.log(event.data);
}
Note that the handle we send is -1, because we are in the global context.
Let's send an OpenDoc method message to open an app:
{
"method": "OpenDoc",
"handle": -1,
"params": [
"4e19dc36-2020-4435-bb96-fe3c613207c7"
],
"jsonrpc": "2.0",
"id": 2
}
We receive the following response:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"qReturn": {
"qType": "Doc",
"qHandle": 1,
"qGenericId":"4e19dc36-2020-4435-bb96-fe3c613207c7"
}
}
"change":[1]
}
Notice that now the handle is 1. This indicates that our engine session is bound to this particular app, and we can now call methods from the App class (and other classes, as we traverse the object tree). If we want work on a different app, we must close this WebSocket and open a new one.
Example 2: Connect directly to Qlik Engine JSON API using certificates
Let's look at another Node.js example where we connect directly to the engine and append engine data to a file.
const WebSocket = require('ws');
const path = require('path');
const fs = require('fs');
// Set certPath to the path to the directory that contains the exported client certificates in PEM format.
var certPath = path.join('C:', 'ProgramData', 'Qlik', 'Sense', 'Repository', 'Exported Certificates', '.Local Certificates');
var certificates = {
cert: fs.readFileSync(path.resolve(certPath, 'client.pem')),
key: fs.readFileSync(path.resolve(certPath, 'client_key.pem')),
root: fs.readFileSync(path.resolve(certPath, 'root.pem'))
};
// Open a WebSocket using the engine port (rather than going through the proxy)
// We use the certificates and a built-in Qlik service account
// We connect at the global level, which gives access to APIs in the Global class
const ws = new WebSocket('wss://server.domain.com:4747/app/', {
ca: [certificates.root],
cert: certificates.cert,
key: certificates.key,
headers: {
'X-Qlik-User': 'UserDirectory=internal; UserId=sa_engine'
}
});
engineConnect = function() {
var d = new Date();
console.log('0. Contacting the QIX Engine service...');
return new Promise((resolve, reject) => {
ws.onopen = function (e) {
console.log("2. Connected! WebSocket readyState = " + ws.readyState);
};
ws.onerror = function (e) {
console.log("Error: " + e.message);
};
// Listen for new messages arriving at the client
ws.onmessage = function (e) {
console.log("## Message received: " + e.data);
fs.appendFile('GetEngineInfo.txt', e.data, function(err){
if(err) {
return console.log(err);
}
else {
console.log("GetEngineInfo.txt saved successfully!");
ws.close();
return;
}
});
};
ws.onclose = function (e) {
console.log("WebSocket closed!");
resolve();
};
console.log("1. Websocket created...");
setInterval(function() {
if(ws.readyState == 1) {
resolve()
}
}, 500)
})
};
engineConnect();
We receive the following response:
0. Contacting the QIX Engine service... 1. Websocket created... 2. Connected! WebSocket readyState = 1 ## Message received: {"jsonrpc":"2.0","method":"OnConnected","params":{"qSessionState":"SESSION_CREATED"}} GetEngineInfo.txt saved successfully! Error: read ECONNRESET WebSocket closed!
The engine data is also appended to the GetEngineInfo.txt file.