LiveView JavaScript Client API

Starting with release 2.0.0, TIBCO Live Datamart includes an entirely new JavaScript Client API. The new API focuses on simplicity, conformity to common JavaScript patterns, compatibility with modern JavaScript frameworks, and detailed documentation. Many of the extraneous features included with the first-generation API were removed in an effort to allow API users to take more control and have more freedom to manipulate and display LiveView data in a way that best suits their needs.

The new JavaScript Client API supersedes and replaces the first-generation JavaScript API. The first-generation API is no longer supported by the current LiveView Server, and customers must migrate any existing web-based LiveView client applications to the new API in order to run them on LiveView 2.0.x servers. Full JavaScript Client API Documentation is incorporated into the LiveView documentation set. JavaScript API documentation is also embedded in every running LiveView Server at the path /lv/api. For example: http://localhost:10080/lv/api

The following sections serve as an introduction to the new JavaScript Client API as well as a porting guide for customers who have web-based LiveView clients using the first-generation API.

JavaScript Client API Samples

The new JavaScript Client API is illustrated in the Creating web applications with JavaScript sample shipped with LiveView. To load this sample in StreamBase Studio:

  1. Select FileLoad StreamBase Sample from Studio's top-level menu.

  2. Enter javasc in the filter field to narrow the selection.

  3. Select the sample whose description is Creating web applications with JavaScript from the TIBCO LiveView category.

  4. Click OK.

Follow the instructions in the sample's README.txt file to run the sample project as a LiveView Project. Then open one of the following URLs in a web browser on the same machine:

http://localhost:10080/simple
http://localhost:10080/query-runner
http://localhost:10080/dashboard
http://localhost:10080/ipad

If available, open this last URL from a browser on an iPad, using the network name of the current machine instead of localhost. For example:

http://graemsay.local:10080/ipad

General Architecture

The first-generation JavaScript API focused heavily on events and callback functions. In the background, the API would periodically poll the LiveView Server for updates, and would dispatch events when new or updated data was retrieved. When issuing commands via that API, users could, depending on the command, either pass a callback function to invoke upon command completion, or wait for the corresponding command response event to fire.

The new API does away with events. Instead, control commands (such as connect, subscribe, addAlertRule, and so on) use Promises to simplify handling of asynchronous calls to the server. For those who would prefer to not use Promises, onSuccess and onError callback functions are also available for control commands. Rather than polling the LiveView Server for updates, the new API uses WebSockets to receive data pushed by the server. Data received on the WebSocket is communicated via registered callback functions, specified when subscribing to a query, as described below.

Accessing the JavaScript API

The first-generation API consisted of many, uncompressed script files. Each file had to be individually included in a user's application in order for it to function. Including the first-generation API in a web page would typically require 18 separate <script src lines.

The new API is packaged in a single, minified script file. Inclusion of this file (plus the two required third-party libraries) is all that is required. Including the new API looks like the following:

<script src="/lv-web/api/lib/jquery.min.js"></script>
<script src="/lv-web/api/lib/atmosphere.min.js"></script>
<script src="/lv-web/api/liveview.min.js"></script>

Connecting

Connecting to and interacting with LiveView in the first-generation API required the use of a StreamBase.data.queries.QueryRequests object. The constructor of this object took a configuration object as a parameter that defined the URL to connect to, as well as a set of event-handler callback functions. After invoking initConnection on the QueryRequests object, the API would fire the oninitconnection event, which signaled the user that the server connection had been established and that further interactions (running queries, adding alert rules, and so on) could be performed.

With the new API, users call LiveView.connect and pass an object parameter that defines URL, username, and password. When the connection has been established, the Promise returned by connect will resolve and the connection is passed to the promise resolution handler. With this connection, the user can issue server commands (running queries, adding alert rules, and so on) much like was done in the first-generation API. If using callbacks, the onSuccess function is invoked upon successful connection and the same connection object is passed to it.

Running Queries

With the first-generation API, a few steps were required to run a query. First, the user had to invoke createQuery on a server-connected QueryRequests object. In order to receive query results, the user then had to call startFetchQueryResults on the QueryRequests object to initiate polling for new data. Finally, upon triggering of the oncreatequery event, the user had to call startQuery on the QueryRequests object so that updates for the corresponding query would fire the onupdatequery event.

Using the new API, all a user needs to do is to call subscribe on an active connection object, passing callbacks for query events of interest (such as onSnapshotStart, onSnapshotEnd, onInsert, onUpdate, and onDelete). When an event occurs for the query, the corresponding callback function is invoked, and appropriate data is passed as an argument. The subscribe function is a server command that returns a Promise. Upon successful subscription to the query, the Promise resolves, and the resolution handler is passed a QuerySubscription object that the user can then use to later reference and update the running query.

Managing Query Results

The first-generation API used query result Stores (BaseStore and MemoryStore) that buffered and maintained query results as a service to the user. On analysis, these Stores were not found to add enough value to compensate for their added complexity and memory usage. They have therefore been removed from the new API.

Storage and maintenance of data received from the server is now completely in the hands of users.

Third Party Requirements

The first-generation API used mootools, jQuery, and dojo.

The new API requires jQuery and jQuery Atmosphere.

Code Comparison

Here's a quick code snippet comparing running a basic query using the first-generation and new APIs:

First, the first-generation API:

<script src="/lv-web/StreamBase/sb.js" type="text/javascript"></script>
<script src="/lv-web/js/mootools-core-1.4.5-full-compat.js" type="text/javascript"></script>
<script src="/lv-web/StreamBase/util/Util.js" type="text/javascript"></script>
<script src="/lv-web/StreamBase/util/Constants.js" type="text/javascript"></script>
<script src="/lv-web/StreamBase/event/FastObservable.js" type="text/javascript"></script>
<script src="/lv-web/StreamBase/event/Events.js" type="text/javascript"></script>
<script src="/lv-web/StreamBase/data/RestServer.js" type="text/javascript"></script>
<script src="/lv-web/StreamBase/data/queries/QueryRequests.js" type="text/javascript"></script>
<script src="/lv-web/StreamBase/data/queries/Query.js" type="text/javascript"></script>
<script src="/lv-web/StreamBase/data/Field.js" type="text/javascript"></script>
<script src="/lv-web/StreamBase/data/Table.js" type="text/javascript"></script>
<script src="/lv-web/StreamBase/data/Schema.js" type="text/javascript"></script>
<script src="/lv-web/StreamBase/data/queries/RawDataRow.js" type="text/javascript"></script>
<script src="/lv-web/StreamBase/data/queries/BaseStore.js" type="text/javascript"></script>
<script src="/lv-web/StreamBase/data/queries/MemoryStore.js" type="text/javascript"></script>
<script src="/lv-web/StreamBase/data/queries/RestStore.js" type="text/javascript"></script>
<script src="/lv-web/StreamBase/data/queries/QueryConfig.js" type="text/javascript"></script>
<script src="/lv-web/StreamBase/data/Config.js" type="text/javascript"></script>
<script>
  var server = new StreamBase.data.queries.QueryRequests({
    baseUrl: "/lv/client/",
    listeners: {
      oninitconnection: function(server) {
        server.createQuery('itemsquery', 'SELECT * FROM ItemsInventory');
        server.startFetchQueryResults(750, 1000);
      },
      oncreatequery: function(server, query) {
        server.startQuery(query.getQueryId());
      },
      onupdatequery: function(server, query, delta) {
        console.log('Query ' + query.name + ' got update data ' + JSON.stringify(delta));
      }
    }
  });
  server.initConnection();
</script>

Next, the new API:

<script src="/lv-web/api/lib/jquery.min.js"></script>
<script src="/lv-web/api/lib/jquery.atmosphere.min.js"></script>
<script src="/lv-web/api/liveview.min.js"></script>
<script>
  LiveView.connect({url: '/lv/client/'}).then(
    function(connection){
      connection.subscribe(
        new LiveView.Query('SELECT * FROM ItemsInventory'),
        {
          onInsert: function(result){
            console.log('Got new tuple: ' + JSON.stringify(reuslt.tuple));            
          }
        }
      );
    }
  );
</script>