JavaScript

Deephaven's Open API provides an interface for external applications to access and present data, both through creating new queries or using existing ones. This guide describes how to use the JavaScript API to connect to Deephaven, discover tables, display data, and apply operations like sorting and filtering.

For a hands-on introduction with a complete, runnable example, see the JavaScript Crash Course. For detailed API reference, see the JavaScript API docs.

Key concepts

Before working with the Deephaven JavaScript API, you should understand some foundational web development concepts and how Deephaven's architecture works.

Web development prerequisites

The Deephaven JavaScript API relies on standard web technologies:

  • Promise — A fluent callback API in modern browsers. Most Deephaven API methods that communicate with the server return Promises, allowing you to handle asynchronous operations with .then() or async/await.
  • WebSocket — An outgoing TCP socket connection that can be created by JavaScript code in modern browsers. Deephaven uses WebSockets for real-time communication between your application and the server.
  • Web Worker — A distinct JavaScript process without access to the DOM, allowing work to be done in the background. The Deephaven API uses Web Workers to handle server messages without blocking your UI.

Deephaven architecture

A Deephaven Enterprise installation consists of several servers that your JavaScript client interacts with:

When you connect via the JavaScript API, you authenticate once, and the API automatically manages Auth Tokens for connections to other servers. You don't need to manually handle token exchanges between servers.

How tables work

Deephaven tables have some important characteristics:

  • Table configuration is immutable — Sorting, filtering, or adjusting columns creates a new table rather than modifying the existing one. The API handles this transparently.
  • Viewport-based data loading — Table metadata (size, columns, sorts, filters) is kept up to date automatically, but actual table data only loads when you call setViewport.
  • Two table types — Preemptive tables always send all contents to the client. Non-preemptive tables let you specify which rows and columns you want updates for.

Column types

Each column in a Deephaven table has a type property indicating the Java type of its data. When you read values with row.get(column), the API converts them to appropriate JavaScript types:

  • String — Returned as JavaScript strings.
  • Number types (int, long, double, etc.) — Returned as JavaScript numbers. Note that JavaScript numbers have limited precision, so very large long values may lose precision.
  • Boolean — Returned as JavaScript booleans.
  • DateTime — Deephaven uses nanosecond precision internally. Values are returned as opaque wrapper objects that support toString, valueOf, asNumber (nanoseconds), and asDate (JavaScript Date in milliseconds).

When creating filter values, use the appropriate factory method to ensure type correctness:

  • FilterValue.ofString(value) — For string comparisons.
  • FilterValue.ofNumber(value) — For numeric comparisons, including DateTime values.
  • FilterValue.ofBoolean(value) — For boolean comparisons.

Connection and reconnection

The API provides events to monitor connection state:

  • connect — Fired when the initial connection is established.
  • disconnect — Fired when the connection is lost. Some messages may be delayed until reconnection.
  • reconnect — Fired when the client automatically reconnects to the server.

The API handles reconnection automatically. You don't need to manually reconnect, but you should listen for these events to update your UI appropriately (for example, showing a "reconnecting" indicator).

Error handling

Errors are communicated through requestfailed events on various objects:

  • Client — Errors communicating with the main server.
  • QueryInfo — Errors communicating with a specific worker.
  • Table — Errors during table operations. Recent operations may have failed and need to be reapplied.

Listen for these events to handle errors gracefully:

Performance considerations

To keep your application responsive and minimize server load:

  • Reuse sort and filter objects — When possible, reuse existing Sort and FilterCondition instances rather than creating new ones. The server can optimize operations when it recognizes previously applied sorts and filters.
  • Close unused tables — Call table.close() when you're done with a table to free server resources.
  • Don't retain Row objectsRow objects may be pooled or discarded internally. Always request fresh viewport data rather than caching rows.
  • Size viewport appropriately — Request only the rows you need to display. You can specify an updateIntervalMs parameter to control how often the server sends updates (default is one second).
  • Use subscriptions carefully — Full table subscriptions via table.subscribe can be expensive for large tables. Prefer viewport-based access with setViewport when possible.

Deephaven glossary

  • Auth Token — An identifier from the Authentication server that allows a client to connect to a server and make requests. Tokens are single-use and expire after a configurable period (default is 5 minutes).
  • Open API — Allows access to Deephaven data without using Deephaven's own client.
  • Persistent Query — A scripted query running on a worker, available to multiple users, and manageable through the PQ Controller.
  • Query Config — Describes a Persistent Query, the script running on it, and the tables it makes available to users.
  • Reconnection Token — A signed identifier that allows a client to reconnect without providing credentials again. Must be periodically refreshed.
  • Table Definition — Metadata for a table, describing the columns and their types.

Loading the library

The JavaScript library is tied to the version of the server it connects to, so you typically load it from the server itself. The library resides at /irisapi/irisapi.nocache.js on the web server.

Include this script tag in your HTML file, replacing https://your-deephaven-server/ with your actual server URL:

Connecting and authenticating

To connect to Deephaven, create a dh.Client instance, wait for the connect event, then call login. The following example uses password authentication. Deephaven supports multiple authentication methods — see Authentication for other options like SAML and LDAP.

The login method takes an object with three properties:

  • username — Your Deephaven username.
  • token — Your authentication credential (password, SSO token, etc.).
  • type — The authentication method to use. This must match an auth handler configured on your server.

After authentication, the API automatically manages WebSocket connections and token refreshes. You only need to add callbacks to Promises as needed.

Discovering Persistent Queries

Persistent Queries are collections of tables running on workers. You can discover available queries and subscribe to changes as they're added, removed, or updated.

The following example shows how to retrieve all known Persistent Queries and listen for changes:

The queryInfo object contains:

  • name — The Persistent Query's display name.
  • serial — A unique identifier for this query instance.
  • designated — The designated replica (undefined if the query is not running).
  • designated.objects — An array of objects with name and type properties (e.g., Table, TreeTable, Figure).
  • designated.getTable(name) — A method to retrieve a specific table.

Opening and displaying tables

Connecting to a table can be expensive, so the API uses a lazy loading pattern. The TableSelector class (used by addTable above) stores a reference to the query and table name, then loads the table only when the user clicks. Once loaded, it creates a TableView to display the data.

The following example shows the TableSelector and TableView classes that complete the flow:

Key points:

  • setViewport(startRow, endRow, columns) — Tells the server which rows and columns you want. Data arrives via the updated event.
  • addEventListener — Returns a cleanup function. Call it to stop receiving updates.
  • table.columns — Contains column metadata including names and types.
  • row.get(column) — Retrieves the value for a specific column in a row.

Sorting and filtering

You can extend the TableView class (defined above) with methods to sort and filter data. The table's applySort and applyFilter methods apply the new configuration and return the previously applied sorts or filters (not Promises). The actual data update happens asynchronously — listen for sortchanged, filterchanged, or updated events, or call getViewportData() to wait for new data.

Add these methods to your TableView class:

Example usage

Cloning tables

Use table.copy when you want to apply different sorts or filters without affecting the original table. Each copy:

  • Fires its own events.
  • Maintains its own viewport.
  • Must be closed independently with table.close().

Server operation order

The applySort, applyFilter, and setViewport methods are synchronous setters that queue operations to be processed on the server. The server processes these operations in order, but the methods return immediately — you may continue receiving updates with the old sort/filter until the server applies the change.

To know when a change has taken effect:

  • Events — Listen for sortchanged, filterchanged, or updated events.
  • Promise — Call getViewportData() to get a Promise that resolves with the next viewport update.

Caution

When you change the sort or filter, the current viewport is cleared. You must set a new viewport after each sort or filter change.

When applying a single change, set the viewport immediately after:

When applying multiple changes, set the viewport only after the last change:

Connecting to Core+ queries

Core+ queries use a different protocol than standard Enterprise queries. To work with Core+ tables, you need to dynamically load the Core+ API and create a separate authenticated connection.

The following example shows an extended TableSelector that handles both Enterprise and Core+ queries. Use this version instead of the simpler TableSelector above if your deployment includes Core+ workers:

The Core+ connection flow:

  1. Check the protocol — Query workerKinds to see if the query supports the Community protocol.
  2. Load the API — Dynamically import the Core+ API from queryInfo.designated.jsApiUrl.
  3. Authenticate — Create an auth token via enterpriseClient.createAuthToken and use it to log in to the Core+ client.
  4. Get the connection — Call getAsIdeConnection to get an IDE-like connection.
  5. Fetch the table — Use connection.getObject with the table name and type.

API design principles

The Deephaven JavaScript API is designed to give web developers a familiar experience:

  • Automatic connection management — After logging in, Auth Tokens are maintained automatically. Connections to other servers happen transparently.
  • Mutable table interface — While tables are immutable on the server, the API lets you treat them as mutable objects. It tracks server-side tables internally and creates new ones as needed.
  • Simple size tracking — Total table size is exposed through a property rather than requiring you to track changes across messages.
  • Cell-level formatting — Format information is available as additional detail on each cell, not as hidden columns.
  • Non-blocking operations — Most server communication happens via Web Workers, keeping your UI responsive. Methods that communicate with the server return Promises or fire events.