enigma.js

enigma.js is a library that helps you communicate with the Qlik Associative Engine in JavaScript environments.

Examples of use may be building your own browser-based analytics tools, back-end services, or command-line scripts.

Installation

npm install enigma.js

Get started

The following commands should get you started in a Node.js environment.

Note: you need an API key from your Qlik Sense SaaS tenant to connect successfully.

npm install enigma.js ws

And then save the following snippet to a JavaScript file and execute it with Node.js.

const enigma = require('enigma.js');
const schema = require('enigma.js/schemas/12.612.0');
const WebSocket = require('ws');

const appId = '96d275f8-af88-419b-8090-6f84382efcb8';
const url = \`wss://your-tenant.eu.qlikcloud.com/app/\${appId}\`;

const session = enigma.create({
  schema,
  createSocket: () => new WebSocket(url, {
    authorization: 'bearer <your-api-key>',
  }),
});

// bind traffic events to log what is sent and received on the socket:
session.on('traffic:sent', data => console.log('sent:', data));
session.on('traffic:received', data => console.log('received:', data));

// open the socket and eventually receive the QIX global API, and then close
// the session:
try {
  const global = await session.open();
  console.log('You are connected!');
  await session.close();
  console.log('Session closed!');
} catch (err) {
  console.log('Something went wrong :(', err);
}

Node.js versus browser

enigma.js as a library can be used both in a Node.js environment, as well as in a browser. This enables you to build projects that are portable, with similar behavior on top of enigma.js. But this compatibility also introduces a few differences in configuration that's explained more in detail under the Configuration section.

Promises

Asynchronicity in the JavaScript world is commonly solved by using either promises or callbacks.

enigma.js makes heavy use of promises because this technology gives you several advantages compared to traditional callbacks:

  • cleaner code for the end-user,
  • error handling can be deferred more easily,
  • compatible with emerging standards (async/await).

All generated API methods return a promise.

Read more:

Authentication

enigma.js doesn't handle authentication due to the simple reason that different products and deployments handle it differently. There are, however, a couple of examples for the more common use cases which you can find on the link below.

Read more:

Schemas, the QIX interface

enigma.js uses schemas to generate a programmatic interface against Qlik Associative Engine. Outlined below describes what a schema consists of, and what their purposes are.

An important note is that enigma.js normalizes the QIX method names into camelCasing, while Qlik Associative Engine uses PascalCasing. GetObject in Qlik Associative Engine would be getObject in enigma.js.

enigma.js allows you to invoke QIX methods by either using what's called 'position', which is an array of parameters, or by name, using an object with key/value pairs.

Example of using the different parameters:

doc.getObject('object-id');
doc.getObject({ qId: 'object-id' });

Read more:

QIX classes, or structs

QIX classes are generic object interfaces describing the available QIX methods you may interact with for that type. Depending on the schema version used, there may be a number of different classes available (if you are curious, look at the specific schema file you are using for the available classes and methods). You generally create, retrieve, and remove these from the Doc interface.

Read more:

QIX enums

The Qlik Associative Engine error codes have constants in the schema that you can use to make your error handling code easier to read.

Read more:

Generic object model

This section gives you a brief overview on how the generic object model works. See the links at the end of this section for more in-depth information.

The Qlik Associative Engine uses what' s called the generic object model within an app (also sometimes called a document).

These generic objects all have unique identifiers, and can be interacted with using the QIX interface schema methods.

Consider this:

An app, your-app.qvf, contains generic object properties, data, load scripts, and so on. When you want to interact with that content, you generally use the generic object model. For example, say you want to interact with a generic object with id my-object:

doc.getObject('my-object').then((api) => {
  // api is now an object with QIX interface methods for the GenericObject struct
});

When getObject is invoked, enigma.js sends a request to fetch a handle for that object. Until that session is closed, Qlik Associative Engine notifies you of changes on that handle every time it gets invalidated (either by changes related to the data model referenced in it, or property changes).

Note that these changes are only triggered when the Qlik Associative Engine changes the state from valid to invalid on that handle:

// bind 'changed' event to get notified when the state is invalid':
api.on('changed', () => console.log('The generic object changed'));
// `getLayout` will set the generic object state to 'valid' in Qlik Associative Engine,
// evaluating any hypercubes, expressions, etc. inside it:
api.getLayout().then(() => {
  // 'getProperties' will give you the underlying properties describing
  // the generic object layout, including the hypercube/expression sources etc.:
  api.getProperties().then((props) => {
    // modify some properties to you liking:
    props.someValue = true;
    // 'setProperties' will modify the generic object state from 'valid' to
    // 'invalid' in Qlik Associative Engine, causing a 'changed' event in enigma.js:
    api.setProperties(props).then(() => {
      // the 'changed' event handler above should now have been invoked
    });
  });
})

Read more:

JSON-RPC protocol

The Qlik Associative Engine uses JSON-RPC over websockets for communication. In short, it means that enigma.js gives you an API that's translated into a JSON-RPC request object, and handles the JSON-RPC response sent back from the engine, eventually sending it back to you in a predictable format. See the links below for more details about the protocol.

Read more: